rudy 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+