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.
@@ -1,86 +1,64 @@
1
1
 
2
2
 
3
3
 
4
-
5
-
6
- # :role:
7
- # :env:
8
- # :access_key:
9
- # :secret_key:
10
- # :dbmachine:
11
-
12
-
13
4
  module Rudy
14
5
  module Command
15
6
  class Environment < Rudy::Command::Base
16
7
 
8
+ #---
9
+ # TODO: http://net-ssh.rubyforge.org/ssh/v1/chapter-4.html
10
+ #+++
17
11
 
18
- # Display configuration from the local user data file (~/.rudy).
19
- # This config contains user data which is sent to each EC2 when
20
- # it's created.
21
- #
22
- # The primary purpose of this command is to give other apps a way
23
- # to check various configuration values. (This is probably mostly
24
- # useful on an instance itself).
25
- #
26
- # # Display the default value.
27
- # $ rudy config -d param-name
28
- #
29
- # # Display the value for a specific machine.
30
- # $ rudy -e prod -r db config param-name
31
- #
32
- # # Display all configuration
33
- # $ rudy config --all
34
- #
35
- def config(name=nil)
36
- return unless @config.exists?
37
- puts "Config: #{@config.path}" if @verbose > 0
38
-
39
-
40
- which = @defaults ? @user : machine_name
41
- puts "Machine: #{which}" if @verbose > 0
42
-
43
- return unless @config.userdata && @config.userdata.is_a?(Hash)
44
- #return unless @config.userdata[which] && @config.userdata[which].is_a?(Hash)
45
-
46
- # The .rudy config files have a different structure.
47
- # There's no userdata -> which. Just the config settings.
48
- if Rudy.in_situ?
49
- if name && @config.userdata.has_key?(name)
50
- puts @config.userdata[name]
51
- else
52
- puts @config.to_yaml
53
- end
12
+
13
+ def connect
14
+ check_keys
15
+ machine = find_current_machine
16
+ if @argv.cmd
17
+ cmd = @argv.cmd.is_a?(Array) ? @argv.cmd.join(' ') : @argv.cmd
54
18
  else
55
- if name && @config.userdata.has_key?(which)
56
- value = @config.userdata[which][name.to_s]
57
- puts value if value
58
- elsif @all
59
- puts @config.to_yaml
60
- else
61
- value = @config.userdata[which]
62
- puts value.to_yaml if value
63
- end
19
+ cmd = false
64
20
  end
65
21
 
66
- end
22
+ puts ssh_command(machine[:dns_name], keypairpath, @global.user, cmd, @option.print)
67
23
 
68
-
69
- def connect
24
+ end
25
+
26
+ def copy_valid?
70
27
  check_keys
71
- machine = find_current_machine
72
- ssh machine[:dns_name], keypairpath, user, false, false, false, @print
28
+ raise "No path specified (rudy copy FROM-PATH [FROM-PATH ...] TO-PATH)" unless argv.size >= 2
29
+ true
73
30
  end
74
31
 
75
32
  # +paths+ an array of paths to copy. The last element is the "to" path.
76
- def copy(paths)
77
- check_keys
33
+ def copy
78
34
  machine = find_current_machine
35
+
36
+ paths = @argv
37
+ dest_path = paths.pop
38
+
39
+ if @option.print
40
+ scp_command machine[:dns_name], keypairpath, @global.user, paths, dest_path, @option.remote, false, @option.print
41
+ return
42
+ end
79
43
 
80
- paths = paths.flatten
81
- to_path = paths.pop
44
+ @option.remote = true if @alias == 'download'
45
+ @option.remote = false if @alias == 'upload'
82
46
 
83
- scp machine[:dns_name], keypairpath, user, paths, to_path, @remote, false, @print
47
+ if @alias == 'scp' || @alias == 'copy'
48
+ @alias = 'download' if @option.remote
49
+ @alias = 'upload' unless @option.remote
50
+ end
51
+
52
+ scp do |scp|
53
+ transfers = paths.collect { |path|
54
+ scp.send(@alias, path, dest_path) do |ch, name, sent, total|
55
+ #TODO: Nice printing in place
56
+ #puts "#{name}: #{sent}/#{total}"
57
+ end
58
+
59
+ }
60
+ transfers.each { |trans| trans.wait }
61
+ end
84
62
  end
85
63
 
86
64
 
@@ -5,51 +5,53 @@ module Rudy
5
5
  module Command
6
6
  class Groups < Rudy::Command::Base
7
7
 
8
- def print_groups(name=nil)
9
- name = machine_group if name.nil? && !@all
8
+ def groups(name=@argv.first)
9
+ name = machine_group if name.nil? && !@option.all
10
10
  @ec2.groups.list(name).each do |grp|
11
11
  print_group grp
12
12
  end
13
13
  end
14
14
 
15
- def create_group(name=nil)
16
- name = machine_group if name.nil?
15
+ def create_groups(name=@argv.first)
16
+ name ||= machine_group
17
+ puts "Creating group #{name}"
17
18
  raise "The group #{name} already exists" if @ec2.groups.exists?(name)
18
19
 
19
- puts "Creating group #{name}"
20
20
  @ec2.groups.create(name)
21
21
 
22
- modify_group name
22
+ modify_groups name
23
23
  end
24
24
 
25
- def modify_group(name=nil)
26
- name = machine_group if name.nil?
25
+ def modify_groups(name=@argv.first)
26
+ name ||= machine_group
27
27
  raise "The group #{name} does not exist" unless @ec2.groups.exists?(name)
28
28
 
29
- @addresses = [Rudy::Utils::external_ip_address] if @addresses.nil?
30
- @ports = [22,80,443] if @ports.nil?
31
- @protocols = ["tcp"] if @protocols.nil?
29
+ @option.addresses ||= [Rudy::Utils::external_ip_address]
30
+ @option.ports ||= [22,80,443]
31
+ @option.protocols ||= ["tcp"]
32
32
 
33
33
  # Make sure the IP addresses have ranges
34
- @addresses.collect! { |ip| (ip.match /\/\d+/) ? ip : "#{ip}/32" }
34
+ @option.addresses.collect! { |ip| (ip.match /\/\d+/) ? ip : "#{ip}/32" }
35
35
 
36
- @protocols.each do |protocol|
37
- puts "Adding ports #{@ports.join(',')} (#{protocol}) for #{@addresses.join(', ')}"
38
- @addresses.each do |address|
39
- @ports.each do |port|
36
+ @option.protocols.each do |protocol|
37
+ puts "Adding ports #{@option.ports.join(',')} (#{protocol}) for #{@option.addresses.join(', ')}"
38
+ @option.addresses.each do |address|
39
+ @option.ports.each do |port|
40
40
  @ec2.groups.modify(name, port, port, protocol, address)
41
41
  end
42
42
  end
43
43
  end
44
44
 
45
- print_groups name
45
+ groups name
46
46
  end
47
47
 
48
- def destroy_group(name=nil)
48
+ def destroy_groups(name=@argv.first)
49
+ name ||= machine_group
50
+ puts "Destroying group #{name}"
49
51
  name = machine_group if name.nil?
50
52
  raise "The group #{name} does not exist" unless @ec2.groups.exists?(name)
53
+ exit unless are_you_sure?
51
54
 
52
- puts "Destroying group #{name}"
53
55
  @ec2.groups.destroy(name)
54
56
 
55
57
  end
@@ -5,18 +5,32 @@ module Rudy
5
5
  class Images < Rudy::Command::Base
6
6
 
7
7
 
8
- def print_images
8
+ def images
9
9
  @ec2.images.list.each do |img|
10
10
  print_image img
11
11
  end
12
12
  end
13
13
 
14
- def create_image
14
+ def create_images_valid?
15
+ puts "Make sure the machine is clean. I don't want archive no crud!"
16
+ exit unless are_you_sure?
17
+ true
18
+ end
19
+
20
+
21
+ def prepare_images
22
+ # TODO: Avail hooks for clean an instance
23
+ # Clean off Rudy specific crap.
24
+ end
25
+
26
+
27
+ def create_images
15
28
 
16
- if @user != "root"
17
- puts "This command will be run as root"
18
- @user = "root" # We need to be root for this operation!
19
- end
29
+ switch_user("root")
30
+
31
+ puts "TODO: clean transient rudy crap off of instance before making image!!!"
32
+ # ~/.rudy, /etc/motd, history -c, /etc/hosts, /var/log/rudy*
33
+ exit
20
34
 
21
35
  raise "No EC2 .pem keys provided" unless has_pem_keys?
22
36
  raise "No SSH key provided for #{keypairname}!" unless has_keypair?(keypairname)
@@ -30,33 +44,34 @@ module Rudy
30
44
 
31
45
  puts "The new image will be based on #{machine_group}_01"
32
46
 
33
- @account ||= @account_num
47
+ @option.account ||= @global.account_num
34
48
 
35
- unless @account
49
+ unless @global.account
36
50
  puts "Enter your 12 digit Amazon account number:"
37
- @account = gets.chomp
51
+ @global.account = gets.chomp
38
52
  end
39
53
 
40
- unless @image_name
54
+ unless @option.image_name
41
55
  puts "Enter the image name:"
42
- @image_name = gets.chomp
56
+ @option.image_name = gets.chomp
43
57
  end
44
58
 
45
- unless @bucket_name
59
+ unless @option.bucket_name
46
60
  puts "Enter the S3 bucket that will store the image:"
47
- @bucket_name = gets.chomp
61
+ @option.bucket_name = gets.chomp
48
62
  end
49
63
 
50
- scp machine[:dns_name], keypairpath, user, @ec2_cert, "/mnt/"
51
- scp machine[:dns_name], keypairpath, user, @ec2_private_key, "/mnt/"
64
+ scp_command machine[:dns_name], keypairpath, @global.user, @global.cert, "/mnt/"
65
+ scp_command machine[:dns_name], keypairpath, @global.user, @global.privatekey, "/mnt/"
52
66
 
53
- ssh machine[:dns_name], keypairpath, user, "ec2-bundle-vol -r i386 -p #{@image_name} -k /mnt/pk-*pem -c /mnt/cert*pem -u #{@account}"
54
- ssh machine[:dns_name], keypairpath, user, "ec2-upload-bundle -b #{@bucket_name} -m /tmp/#{@image_name}.manifest.xml -a #{@access_key} -s #{@secret_key}"
67
+ ssh_command machine[:dns_name], keypairpath, @global.user, "ec2-bundle-vol -r i386 -p #{@option.image_name} -k /mnt/pk-*pem -c /mnt/cert*pem -u #{@option.account}"
68
+ ssh_command machine[:dns_name], keypairpath, @global.user, "ec2-upload-bundle -b #{@option.bucket_name} -m /tmp/#{@option.image_name}.manifest.xml -a #{@global.accesskey} -s #{@global.secretkey}"
55
69
 
56
- @ec2.images.register("#{@bucket_name}/#{@image_name}.manifest.xml")
70
+ @ec2.images.register("#{@option.bucket_name}/#{@option.image_name}.manifest.xml")
57
71
  end
58
72
 
59
- def deregister(ami)
73
+ def deregister
74
+ ami = @argv.first
60
75
  raise "You must supply an AMI ID (ami-XXXXXXX)" unless ami
61
76
  puts "Deregistering AMI: #{ami}"
62
77
 
@@ -1,11 +1,42 @@
1
-
1
+ #
2
+ #
3
+ #
4
+ #
5
+ #
6
+ #
7
+ #
8
+ #
9
+ #
10
+ #
11
+ #
2
12
 
3
13
  module Rudy
4
14
  module Command
5
15
  class Instances < Rudy::Command::Base
6
16
 
7
- def print_instances(filter=nil)
8
- filter = machine_group if filter.nil? && !@all
17
+ def restart_instances_valid?
18
+ raise "No instance ID provided" if @argv.filter.nil?
19
+ raise "No EC2 .pem keys provided" unless has_pem_keys?
20
+ raise "No SSH key provided for #{@global.user}!" unless has_keypair?
21
+ raise "No SSH key provided for root!" unless has_keypair?(:root)
22
+
23
+
24
+ @list = @ec2.instances.list(machine_group)
25
+ raise "#{@argv.filter} is not in the current machine group" unless @list.has_key?(@argv.filter)
26
+
27
+ raise "I will not help you destroy production!" if @global.environment == "prod" # TODO: use_caution?, locked?
28
+
29
+ exit unless are_you_sure?(5)
30
+ true
31
+ end
32
+ def restart_instances
33
+ puts "Restarting #{@argv.filter}!"
34
+ @ec2.instances.restart @argv.filter
35
+ end
36
+
37
+ def instances
38
+ filter = @argv.first
39
+ filter = machine_group if filter.nil? && !@option.all
9
40
  if instance_id?(filter)
10
41
  inst = @ec2.instances.get(filter)
11
42
  raise "The instance #{filter} does not exist" if inst.empty?
@@ -26,9 +57,17 @@ module Rudy
26
57
 
27
58
  end
28
59
 
29
- def destroy_instances(filter=nil)
30
- raise "No instance ID or group name provided" if filter.nil?
31
- raise "I will not help you destroy production!" if @environment == "prod" || filter =~ /^prod/
60
+ def destroy_instances_valid?
61
+ filter = argv.first
62
+ raise "No instance ID provided" if filter.nil?
63
+ raise "I will not help you destroy production!" if @global.environment == "prod" || filter =~ /^prod/
64
+ exit unless are_you_sure?
65
+ true
66
+ end
67
+
68
+ def destroy_instances
69
+ filter = argv.first
70
+
32
71
  if @ec2.groups.exists?(filter)
33
72
  list = @ec2.instances.list(filter)
34
73
  raise "The group #{filter} has no running instances" if list.empty?
@@ -39,92 +78,7 @@ module Rudy
39
78
  puts "Destroying #{instance}!"
40
79
  @ec2.instances.destroy instance
41
80
  end
42
-
43
- def start_instance
44
- @image ||= machine_image
45
-
46
- @user = "root"
47
-
48
- rig = @ec2.instances.list(machine_group)
49
- raise "There is already an instance running in #{machine_group}" unless rig.empty?
50
- raise "No SSH key provided for #{keypairname}!" unless has_keypair?(keypairname)
51
- raise "SSH key provided but cannot be found! (#{keypairpath})" unless File.exists?(keypairpath)
52
-
53
-
54
- machine_data = {
55
- # Give the machine an identity
56
- :zone => @zone,
57
- :environment => @environment,
58
- :role => @role,
59
- :position => @position,
60
-
61
- # Add hosts to the /etc/hosts file
62
- :hosts => {
63
- :dbmaster => "127.0.0.1",
64
- },
65
-
66
- :userdata => {}
67
- }
68
-
69
- # Populate userdata with settings from ~/.rudy
70
- if @config.userdata.is_a?(Hash) && !@config.userdata.empty?
71
- # Build a set of parameters for each user on the requested
72
- # machine. Set default values first and overwrite. (TODO)
73
- @config.userdata.each_pair do |n,hash|
74
- user = n # TODO: should be prepared to parse "us-east-1b-stage-app-rudy" and "us-east-1b-stage-app-01-rudy"
75
- machine_data[:userdata][user] = hash
76
- end
77
- end
78
-
79
- puts "Starting an instance in #{machine_group}"
80
- puts "with userdata:", machine_data.to_yaml
81
-
82
- instances = @ec2.instances.create(@image, machine_group.to_s, File.basename(keypairpath), machine_data.to_yaml, @zone)
83
- inst = instances.first
84
- id, state = inst[:aws_instance_id], inst[:aws_state]
85
-
86
- if @address
87
- puts "Associating #{@address} to #{id}"
88
- @ec2.addresses.associate(id, @address)
89
- end
90
-
91
- print "Waiting for #{id} to become available"
92
-
93
- while @ec2.instances.pending?(id)
94
- sleep 2
95
- print '.'
96
- STDOUT.flush
97
- end
98
-
99
- machine = @ec2.instances.get(id)
100
-
101
- puts " It's up!"
102
- print "Waiting for SSH daemon at #{machine[:dns_name]}"
103
- while !Rudy::Utils.service_available?(machine[:dns_name], 22)
104
- print '.'
105
- STDOUT.flush
106
- end
107
- puts " It's up!"
108
-
109
- print "Looking for disk metadata for #{machine[:aws_availability_zone]}... "
110
- disks = Rudy::MetaData::Disk.list(@sdb, machine[:aws_availability_zone], @environment, @role, @position)
111
-
112
- if disks.empty?
113
- puts "None"
114
- else
115
- puts "#{disks.size} disk(s)."
116
- disks.each do |disk|
117
-
118
- do_dirty_disk_volume_deeds(disk, machine)
119
- end
120
- end
121
-
122
- puts
123
- ssh machine[:dns_name], keypairpath, user, "df -h" # Display current mounts
124
- puts
125
- puts "Done!"
126
- end
127
-
81
+
128
82
  end
129
83
  end
130
84
  end
@@ -0,0 +1,161 @@
1
+
2
+
3
+ module Rudy
4
+ module Command
5
+ class Machines < Rudy::Command::Base
6
+
7
+
8
+ def shutdown_valid?
9
+ raise "No EC2 .pem keys provided" unless has_pem_keys?
10
+ raise "No SSH key provided for #{@global.user}!" unless has_keypair?
11
+ raise "No SSH key provided for root!" unless has_keypair?(:root)
12
+
13
+ @list = @ec2.instances.list(machine_group)
14
+ raise "No machines running in #{machine_group}" unless @list && !@list.empty?
15
+
16
+ raise "I will not help you ruin production!" if @global.environment == "prod" # TODO: use_caution?, locked?
17
+
18
+ true
19
+ end
20
+
21
+
22
+ def shutdown
23
+ puts "Shutting down #{machine_group}: #{@list.keys.join(', ')}".att(:bright)
24
+ switch_user("root")
25
+ puts "This command also affects the volumes attached to the instances! (according to your routines config)"
26
+ exit unless are_you_sure?(5)
27
+
28
+ execute_routines(@list.values, :shutdown, :before)
29
+
30
+ execute_disk_routines(@list.values, :shutdown)
31
+
32
+ puts "Terminating instances..."
33
+ @ec2.instances.destroy @list.keys
34
+ sleep 5
35
+
36
+ execute_routines(@list.values, :shutdown, :after)
37
+
38
+ puts "Done!"
39
+ end
40
+
41
+ def startup_valid?
42
+ rig = @ec2.instances.list(machine_group)
43
+ raise "There is already an instance running in #{machine_group}" if rig && !rig.empty?
44
+ raise "No SSH key provided for #{keypairname}!" unless has_keypair?
45
+ true
46
+ end
47
+ def startup
48
+ puts "Starting a machine in #{machine_group}".att(:bright)
49
+ switch_user("root")
50
+ exit unless are_you_sure?(3)
51
+
52
+ #execute_routines([], :startup, :before_local)
53
+
54
+ @option.image ||= machine_image
55
+
56
+ instances = @ec2.instances.create(@option.image, machine_group.to_s, File.basename(keypairpath), machine_data.to_yaml, @global.zone)
57
+ inst = instances.first
58
+
59
+ if @option.address ||= machine_address
60
+ puts "Associating #{@option.address} to #{inst[:aws_instance_id]}"
61
+ @ec2.addresses.associate(inst[:aws_instance_id], @option.address)
62
+ end
63
+
64
+ wait_for_machine(inst[:aws_instance_id])
65
+ inst = @ec2.instances.get(inst[:aws_instance_id])
66
+
67
+ #inst = @ec2.instances.list(machine_group).values
68
+
69
+ execute_disk_routines(inst, :startup)
70
+ execute_routines(inst, :startup, :after)
71
+
72
+ puts "Done!"
73
+ end
74
+
75
+ def restart_valid?
76
+ shutdown_valid?
77
+ end
78
+ def restart
79
+ puts "Restarting #{machine_group}: #{@list.keys.join(', ')}".att(:bright)
80
+ switch_user("root")
81
+ exit unless are_you_sure?(5)
82
+
83
+ @list.each do |id, inst|
84
+ execute_routines(@list.values, :restart, :before)
85
+ end
86
+
87
+ puts "Restarting instances: #{@list.keys.join(', ')}".att(:bright)
88
+ @ec2.instances.restart @list.keys
89
+ sleep 10 # Wait for state to change and SSH to shutdown
90
+
91
+ @list.keys.each do |id|
92
+ wait_for_machine(id)
93
+ end
94
+
95
+ execute_disk_routines(@list.values, :restart)
96
+
97
+ @list.each do |id, inst|
98
+ execute_routines(@list.values, :restart, :after)
99
+ end
100
+
101
+ puts "Done!"
102
+ end
103
+
104
+
105
+ def status_valid?
106
+ raise "No EC2 .pem keys provided" unless has_pem_keys?
107
+ raise "No SSH key provided for #{@global.user}!" unless has_keypair?
108
+ raise "No SSH key provided for root!" unless has_keypair?(:root)
109
+
110
+ @list = @ec2.instances.list(machine_group)
111
+ raise "No machines running in #{machine_group}" unless @list
112
+ true
113
+ end
114
+ def status
115
+ puts "There are no machines running in #{machine_group}" if @list.empty?
116
+ @list.each_pair do |id, inst|
117
+ print_instance inst
118
+ end
119
+ end
120
+
121
+
122
+ #def update_valid?
123
+ # raise "No EC2 .pem keys provided" unless has_pem_keys?
124
+ # raise "No SSH key provided for #{@global.user}!" unless has_keypair?
125
+ # raise "No SSH key provided for root!" unless has_keypair?(:root)
126
+ #
127
+ # @script = File.join(RUDY_HOME, 'support', 'rudy-ec2-startup')
128
+ #
129
+ # raise "Cannot find startup script" unless File.exists?(@script)
130
+ #
131
+ #
132
+ # true
133
+ #end
134
+ #
135
+ #
136
+ #def update
137
+ # puts "Updating Rudy "
138
+ # switch_user("root")
139
+ #
140
+ # exit unless are_you_sure?
141
+ # scp do |scp|
142
+ # puts "Updating Rudy startup script (#{@script})"
143
+ # scp.upload!(@script, "/etc/init.d/") do |ch, name, sent, total|
144
+ # puts "#{name}: #{sent}/#{total}"
145
+ # end
146
+ # end
147
+ #
148
+ # ssh do |session|
149
+ # session.exec!("chmod 700 /etc/init.d/rudy-ec2-startup")
150
+ # puts "Installing Rudy (#{Rudy::VERSION})"
151
+ # puts session.exec!("gem sources -a http://gems.github.com")
152
+ # puts session.exec!("gem install --no-ri --no-rdoc solutious-rudy -v #{Rudy::VERSION}")
153
+ # end
154
+ #end
155
+
156
+
157
+ end
158
+ end
159
+ end
160
+
161
+