rudy 0.8.5 → 0.9.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 +110 -18
- data/README.rdoc +40 -44
- data/Rudyfile +35 -50
- data/bin/rudy +88 -57
- data/bin/rudy-ec2 +2 -16
- data/bin/rudy-s3 +0 -10
- data/bin/rudy-sdb +11 -12
- data/lib/rudy.rb +59 -91
- data/lib/rudy/aws.rb +4 -45
- data/lib/rudy/aws/ec2.rb +57 -20
- data/lib/rudy/aws/ec2/address.rb +10 -11
- data/lib/rudy/aws/ec2/group.rb +10 -9
- data/lib/rudy/aws/ec2/image.rb +8 -8
- data/lib/rudy/aws/ec2/instance.rb +18 -19
- data/lib/rudy/aws/ec2/keypair.rb +14 -19
- data/lib/rudy/aws/ec2/snapshot.rb +16 -9
- data/lib/rudy/aws/ec2/volume.rb +39 -26
- data/lib/rudy/aws/ec2/zone.rb +5 -4
- data/lib/rudy/aws/s3.rb +2 -1
- data/lib/rudy/aws/sdb.rb +35 -86
- data/lib/rudy/backups.rb +24 -0
- data/lib/rudy/cli.rb +5 -131
- data/lib/rudy/cli/aws/ec2/addresses.rb +19 -27
- data/lib/rudy/cli/aws/ec2/candy.rb +45 -20
- data/lib/rudy/cli/aws/ec2/groups.rb +9 -13
- data/lib/rudy/cli/aws/ec2/images.rb +5 -133
- data/lib/rudy/cli/aws/ec2/instances.rb +25 -25
- data/lib/rudy/cli/aws/ec2/keypairs.rb +7 -11
- data/lib/rudy/cli/aws/ec2/snapshots.rb +5 -9
- data/lib/rudy/cli/aws/ec2/volumes.rb +22 -23
- data/lib/rudy/cli/aws/ec2/zones.rb +2 -3
- data/lib/rudy/cli/aws/sdb/domains.rb +5 -6
- data/lib/rudy/cli/aws/sdb/objects.rb +33 -0
- data/lib/rudy/cli/aws/sdb/select.rb +23 -0
- data/lib/rudy/cli/backups.rb +38 -0
- data/lib/rudy/cli/base.rb +104 -0
- data/lib/rudy/cli/candy.rb +1 -2
- data/lib/rudy/cli/config.rb +20 -7
- data/lib/rudy/cli/disks.rb +7 -9
- data/lib/rudy/cli/execbase.rb +56 -0
- data/lib/rudy/cli/machines.rb +242 -45
- data/lib/rudy/cli/metadata.rb +24 -10
- data/lib/rudy/cli/networks.rb +34 -0
- data/lib/rudy/cli/routines.rb +32 -6
- data/lib/rudy/cli/status.rb +60 -0
- data/lib/rudy/config.rb +55 -32
- data/lib/rudy/config/objects.rb +44 -30
- data/lib/rudy/disks.rb +25 -0
- data/lib/rudy/exceptions.rb +99 -0
- data/lib/rudy/global.rb +67 -28
- data/lib/rudy/guidelines.rb +3 -2
- data/lib/rudy/huxtable.rb +67 -58
- data/lib/rudy/machines.rb +41 -263
- data/lib/rudy/metadata.rb +212 -38
- data/lib/rudy/metadata/backup.rb +123 -78
- data/lib/rudy/metadata/disk.rb +153 -170
- data/lib/rudy/metadata/machine.rb +179 -0
- data/lib/rudy/mixins.rb +2 -1
- data/lib/rudy/mixins/hash.rb +3 -1
- data/lib/rudy/mixins/symbol.rb +8 -0
- data/lib/rudy/routines.rb +127 -344
- data/lib/rudy/routines/base.rb +229 -0
- data/lib/rudy/routines/handlers/base.rb +48 -0
- data/lib/rudy/routines/handlers/depends.rb +49 -0
- data/lib/rudy/routines/handlers/disks.rb +249 -0
- data/lib/rudy/routines/handlers/group.rb +44 -0
- data/lib/rudy/routines/handlers/host.rb +70 -0
- data/lib/rudy/routines/handlers/keypair.rb +70 -0
- data/lib/rudy/routines/handlers/machines.rb +15 -0
- data/lib/rudy/routines/handlers/script.rb +85 -0
- data/lib/rudy/routines/handlers/user.rb +45 -0
- data/lib/rudy/routines/passthrough.rb +19 -23
- data/lib/rudy/routines/reboot.rb +98 -50
- data/lib/rudy/routines/shutdown.rb +65 -14
- data/lib/rudy/routines/startup.rb +112 -17
- data/lib/rudy/utils.rb +35 -68
- data/rudy.gemspec +82 -25
- data/tryouts/01_mixins/01_hash_tryouts.rb +20 -0
- data/tryouts/10_require_time/10_rudy_tryouts.rb +33 -0
- data/tryouts/10_require_time/15_global_tryouts.rb +58 -0
- data/tryouts/12_config/10_load_config_tryouts.rb +43 -0
- data/tryouts/12_config/20_defaults_tryouts.rb +16 -0
- data/tryouts/12_config/30_accounts_tryouts.rb +17 -0
- data/tryouts/12_config/40_machines_tryouts.rb +53 -0
- data/tryouts/12_config/50_commands_tryouts.rb +17 -0
- data/tryouts/12_config/60_routines_tryouts.rb +16 -0
- data/tryouts/15_huxtable/10_huxtable_tryouts.rb +47 -0
- data/tryouts/15_huxtable/20_user_tryouts.rb +47 -0
- data/tryouts/20_simpledb/10_domains_tryouts.rb +36 -0
- data/tryouts/20_simpledb/20_objects_tryouts.rb +56 -0
- data/tryouts/25_ec2/10_keypairs_tryouts.rb +54 -0
- data/tryouts/25_ec2/20_groups_tryouts.rb +56 -0
- data/tryouts/25_ec2/21_groups_authorize_address_tryouts.rb +53 -0
- data/tryouts/25_ec2/22_groups_authorize_account_tryouts.rb +54 -0
- data/tryouts/25_ec2/30_addresses_tryouts.rb +42 -0
- data/tryouts/25_ec2/40_volumes_tryouts.rb +53 -0
- data/tryouts/25_ec2/50_snapshots_tryouts.rb +75 -0
- data/tryouts/26_ec2_instances/10_instance_tryouts.rb +107 -0
- data/tryouts/26_ec2_instances/50_images_tryouts.rb +7 -0
- data/tryouts/30_metadata/10_include_tryouts.rb +45 -0
- data/tryouts/30_metadata/13_object_tryouts.rb +19 -0
- data/tryouts/30_metadata/50_disk_tryouts.rb +115 -0
- data/tryouts/30_metadata/51_disk_digest_tryouts.rb +24 -0
- data/tryouts/30_metadata/53_disk_list_tryouts.rb +35 -0
- data/tryouts/30_metadata/56_disk_volume_tryouts.rb +68 -0
- data/tryouts/30_metadata/60_backup_tryouts.rb +101 -0
- data/tryouts/30_metadata/63_backup_list_tryouts.rb +38 -0
- data/tryouts/30_metadata/64_backup_disk_tryouts.rb +65 -0
- data/tryouts/30_metadata/66_backup_snapshot_tryouts.rb +76 -0
- data/tryouts/30_metadata/70_machine_tryouts.rb +85 -0
- data/tryouts/30_metadata/73_machine_list_tryouts.rb +58 -0
- data/tryouts/30_metadata/76_machine_instance_tryouts.rb +64 -0
- data/tryouts/30_metadata/77_machines_tryouts.rb +45 -0
- data/tryouts/40_routines/10_keypair_handler_tryouts.rb +52 -0
- data/tryouts/40_routines/11_group_handler_tryouts.rb +36 -0
- data/tryouts/80_cli/10_rudyec2_tryouts.rb +8 -0
- data/tryouts/80_cli/60_rudy_tryouts.rb +41 -0
- data/tryouts/exploration/console.rb +91 -0
- data/tryouts/exploration/machine.rb +23 -0
- data/tryouts/failer +6 -0
- metadata +116 -32
- data/bin/ird +0 -153
- data/lib/rudy/metadata/backups.rb +0 -67
- data/lib/rudy/metadata/debug.rb +0 -38
- data/lib/rudy/metadata/disks.rb +0 -67
- data/lib/rudy/metadata/objectbase.rb +0 -108
- data/lib/rudy/routines/helper.rb +0 -76
- data/lib/rudy/routines/helpers/dependshelper.rb +0 -34
- data/lib/rudy/routines/helpers/diskhelper.rb +0 -403
- data/lib/rudy/routines/helpers/scripthelper.rb +0 -197
- data/lib/rudy/routines/helpers/userhelper.rb +0 -37
- data/support/rudy-ec2-startup +0 -200
@@ -7,11 +7,10 @@ module AWS; module EC2;
|
|
7
7
|
|
8
8
|
|
9
9
|
def zones
|
10
|
-
|
11
|
-
rzone.list_as_hash(@argv.name).each_value do |zon|
|
10
|
+
Rudy::AWS::EC2::Zones.list_as_hash(@argv.name).each_value do |zon|
|
12
11
|
puts zon.dump(@@global.format)
|
13
12
|
end
|
14
|
-
puts "No zones" unless
|
13
|
+
puts "No zones" unless Rudy::AWS::EC2::Zones.any?
|
15
14
|
end
|
16
15
|
|
17
16
|
|
@@ -4,32 +4,31 @@ module Rudy; module CLI;
|
|
4
4
|
module AWS; module SDB;
|
5
5
|
|
6
6
|
class Domains < Rudy::CLI::CommandBase
|
7
|
-
|
8
|
-
|
7
|
+
|
9
8
|
def domains
|
10
|
-
sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
11
|
-
domains = sdb.list_domains
|
9
|
+
@sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
10
|
+
domains = @sdb.list_domains
|
12
11
|
puts domains
|
13
12
|
puts "No domains" if domains.nil? || domains.empty?
|
14
13
|
end
|
15
14
|
|
16
15
|
def domains_create_valid?
|
17
|
-
@sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
18
16
|
raise "No name specified" unless @argv.name
|
19
17
|
true
|
20
18
|
end
|
21
19
|
def domains_create
|
20
|
+
@sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
22
21
|
@sdb.create_domain @argv.name
|
23
22
|
execute_check(:low)
|
24
23
|
domains
|
25
24
|
end
|
26
25
|
|
27
26
|
def domains_destroy_valid?
|
28
|
-
@sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
29
27
|
raise "No name specified" unless @argv.name
|
30
28
|
true
|
31
29
|
end
|
32
30
|
def domains_destroy
|
31
|
+
@sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
33
32
|
execute_check(:medium)
|
34
33
|
@sdb.destroy_domain @argv.name
|
35
34
|
domains
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Rudy; module CLI;
|
4
|
+
module AWS; module SDB;
|
5
|
+
|
6
|
+
class Objects < Rudy::CLI::CommandBase
|
7
|
+
|
8
|
+
|
9
|
+
def objects_valid?
|
10
|
+
raise "Must supply domain" if @argv.empty?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
def objects
|
14
|
+
@sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
15
|
+
|
16
|
+
if @argv.key.nil?
|
17
|
+
query = "select * from #{@argv.name}"
|
18
|
+
items = @sdb.select query
|
19
|
+
else
|
20
|
+
items = [@sdb.get( @argv.name, @argv.key)]
|
21
|
+
end
|
22
|
+
|
23
|
+
exit unless items
|
24
|
+
|
25
|
+
items.each do |i|
|
26
|
+
p i
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end; end
|
33
|
+
end; end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
module Rudy; module CLI;
|
3
|
+
module AWS; module SDB;
|
4
|
+
|
5
|
+
class Select < Rudy::CLI::CommandBase
|
6
|
+
|
7
|
+
def query_valid?
|
8
|
+
raise "No select query supplied" if @argv.empty?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def query
|
13
|
+
@sdb = Rudy::AWS::SDB.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
14
|
+
results = @sdb.select @argv.query
|
15
|
+
return if results.nil?
|
16
|
+
results.each do |r|
|
17
|
+
p r
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end; end
|
23
|
+
end; end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Rudy
|
4
|
+
module CLI
|
5
|
+
class Backups < Rudy::CLI::CommandBase
|
6
|
+
|
7
|
+
|
8
|
+
def backups
|
9
|
+
more, less = {}, []
|
10
|
+
less = [:environment, :role] if @option.all
|
11
|
+
# We first get the disk metadata
|
12
|
+
b_list = Rudy::Backups.list(more, less) || []
|
13
|
+
b_list.each do |back|
|
14
|
+
puts @global.verbose > 0 ? "#{back.name}: #{back.inspect}" : back.name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def backups_wash
|
19
|
+
dirt = (Rudy::Backups.list || []).select { |b| !b.snapshot_exists? }
|
20
|
+
if dirt.empty?
|
21
|
+
puts "Nothing to wash in #{current_machine_group}"
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
puts "The following backup metadata will be deleted:"
|
26
|
+
puts dirt.collect {|b| b.name }
|
27
|
+
|
28
|
+
execute_check(:medium)
|
29
|
+
|
30
|
+
dirt.each do |b|
|
31
|
+
b.destroy(:force)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Rudy::CLI
|
4
|
+
|
5
|
+
class CommandBase < Drydock::Command
|
6
|
+
include Rudy::Huxtable
|
7
|
+
|
8
|
+
attr_reader :config
|
9
|
+
|
10
|
+
protected
|
11
|
+
def init
|
12
|
+
|
13
|
+
if Drydock.debug?
|
14
|
+
#Caesars.enable_debug
|
15
|
+
Rudy.enable_debug
|
16
|
+
end
|
17
|
+
|
18
|
+
# The CLI wants output!
|
19
|
+
Rudy::Huxtable.update_logger STDOUT
|
20
|
+
|
21
|
+
# Send The Huxtables the global values from the command-line
|
22
|
+
Rudy::Huxtable.update_global @global
|
23
|
+
|
24
|
+
# Reload configuration. This must come after update_global
|
25
|
+
# so it will catch the @@global.config path (if supplied).
|
26
|
+
begin
|
27
|
+
Rudy::Huxtable.update_config
|
28
|
+
rescue Caesars::SyntaxError => ex
|
29
|
+
STDERR.puts ex.message
|
30
|
+
STDERR.puts ex.backtrace if @@global.verbose > 0
|
31
|
+
exit 81
|
32
|
+
end
|
33
|
+
|
34
|
+
@@global.nocolor ? String.disable_color : String.enable_color
|
35
|
+
@@global.auto ? Annoy.enable_skip : Annoy.disable_skip
|
36
|
+
|
37
|
+
# ANSI codes look like garbage in DOS
|
38
|
+
if Rudy.sysinfo.os.to_s == 'win32'
|
39
|
+
String.disable_color
|
40
|
+
raise Rudy::Error, 'Ruby 1.9 is not supported (yet)' if Rudy.sysinfo.ruby == [1,9,1]
|
41
|
+
end
|
42
|
+
|
43
|
+
unless @@global.accesskey && @@global.secretkey
|
44
|
+
STDERR.puts "No AWS credentials. Check your configs!"
|
45
|
+
STDERR.puts "Try: rudy init"
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
|
49
|
+
if @@global.environment =~ /^prod/ && Rudy.debug?
|
50
|
+
puts Rudy::Utils.banner("PRODUCTION ACCESS IS DISABLED IN DEBUG MODE")
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
|
54
|
+
if @@global.verbose >= 4 # -vvvv
|
55
|
+
format = @@global.format == :json ? :json : :yaml
|
56
|
+
gcopy = @@global.dup
|
57
|
+
gcopy.secretkey = "[HIDDEN]"
|
58
|
+
puts "# GLOBALS: ", gcopy.dump(format)
|
59
|
+
end
|
60
|
+
|
61
|
+
Rudy::Metadata.connect @@global.accesskey, @@global.secretkey, @@global.region
|
62
|
+
Rudy::AWS::EC2.connect @@global.accesskey, @@global.secretkey, @@global.region
|
63
|
+
end
|
64
|
+
|
65
|
+
def execute_action(emsg="Failed", &action)
|
66
|
+
begin
|
67
|
+
ret = action.call
|
68
|
+
raise emsg unless ret
|
69
|
+
ret
|
70
|
+
rescue Rudy::AWS::EC2::NoAMI => ex
|
71
|
+
raise Drydock::OptError.new('-a', @alias)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def execute_check(level=:medium)
|
76
|
+
ret = Annoy.are_you_sure?(level)
|
77
|
+
exit 0 unless ret
|
78
|
+
ret
|
79
|
+
end
|
80
|
+
|
81
|
+
# Print a default header to the screen for every command.
|
82
|
+
#
|
83
|
+
def print_header
|
84
|
+
|
85
|
+
# Send The Huxtables the global values again because they could be
|
86
|
+
# updated after initialization but before the command was executed
|
87
|
+
Rudy::Huxtable.update_global @global
|
88
|
+
|
89
|
+
puts Rudy::CLI.generate_header(@@global, @@config) if @@global.print_header
|
90
|
+
|
91
|
+
unless @@global.quiet
|
92
|
+
if @@global.environment == "prod"
|
93
|
+
msg = "YOU ARE PLAYING WITH PRODUCTION"
|
94
|
+
puts Rudy::Utils.banner(msg, :normal), $/
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def machine_separator(name, awsid)
|
100
|
+
('%s %-50s awsid: %s ' % [$/, name, awsid]).att(:reverse)
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
data/lib/rudy/cli/candy.rb
CHANGED
data/lib/rudy/cli/config.rb
CHANGED
@@ -21,17 +21,20 @@ module Rudy
|
|
21
21
|
#
|
22
22
|
# It will return the most specific configuration available. If the
|
23
23
|
# attribute isn'e found it will check each parent for the same attribute.
|
24
|
-
#
|
24
|
+
# e.g. if [prod][app][ami] is not available, it will check [prod][ami]
|
25
25
|
# and then [ami].
|
26
26
|
#
|
27
|
-
# # Display the value for a specific machine.
|
28
|
-
# $ rudy -e prod -r db config param-name
|
29
|
-
#
|
30
27
|
# # Display all configuration
|
31
28
|
# $ rudy config --all
|
32
29
|
#
|
30
|
+
# # Display just machines
|
31
|
+
# $ rudy config --defaults
|
32
|
+
#
|
33
33
|
def config
|
34
|
-
|
34
|
+
|
35
|
+
# TODO: Re-enable:
|
36
|
+
# # Display the value for a specific machine.
|
37
|
+
# $ rudy -e prod -r db config param-name
|
35
38
|
|
36
39
|
if @@config.nil? || @@config.empty?
|
37
40
|
return if @@global.quiet
|
@@ -58,7 +61,11 @@ module Rudy
|
|
58
61
|
types.each do |conftype|
|
59
62
|
puts "# #{conftype.to_s.upcase}"
|
60
63
|
next unless @@config[conftype] # Nothing to output
|
61
|
-
|
64
|
+
if conftype == :accounts
|
65
|
+
skey = @@config[conftype][:aws][:secretkey]
|
66
|
+
@@config[conftype][:aws][:secretkey] = hide_secret_key(skey)
|
67
|
+
end
|
68
|
+
|
62
69
|
puts @@config[conftype].to_hash.send(outform)
|
63
70
|
end
|
64
71
|
end
|
@@ -73,10 +80,16 @@ module Rudy
|
|
73
80
|
end
|
74
81
|
gtmp = @@global.clone
|
75
82
|
gtmp.format = "yaml" if gtmp.format == :s || gtmp.format == :string
|
76
|
-
gtmp.
|
83
|
+
gtmp.secretkey = hide_secret_key(gtmp.secretkey)
|
77
84
|
puts gtmp.dump(gtmp.format)
|
78
85
|
end
|
79
86
|
|
87
|
+
private
|
88
|
+
def hide_secret_key(skey)
|
89
|
+
skey = skey.to_s
|
90
|
+
"%s%s%s" % [skey[0], '.'*18, skey[-1]]
|
91
|
+
end
|
92
|
+
|
80
93
|
end
|
81
94
|
end
|
82
95
|
end
|
data/lib/rudy/cli/disks.rb
CHANGED
@@ -6,16 +6,14 @@ module Rudy
|
|
6
6
|
|
7
7
|
|
8
8
|
def disks
|
9
|
-
|
10
|
-
rback = Rudy::Backups.new
|
11
|
-
more, less = [], []
|
9
|
+
more, less = {}, []
|
12
10
|
less = [:environment, :role] if @option.all
|
13
11
|
# We first get the disk metadata
|
14
|
-
disk_list =
|
12
|
+
disk_list = Rudy::Disks.list(more, less) || []
|
15
13
|
# If there are no disks currently, there could be backups
|
16
14
|
# so we grab those to create a list of disks.
|
17
15
|
if @option.backups
|
18
|
-
backups =
|
16
|
+
backups = Rudy::Backups.list(more, less) || []
|
19
17
|
backups.each_with_index do |b, index|
|
20
18
|
disk_list << b.disk
|
21
19
|
end
|
@@ -27,7 +25,7 @@ module Rudy
|
|
27
25
|
seen << d.name
|
28
26
|
puts @@global.verbose > 0 ? d.inspect : d.dump(@@global.format)
|
29
27
|
if @option.backups
|
30
|
-
d.
|
28
|
+
d.backups.each_with_index do |b, index|
|
31
29
|
puts ' %s' % b.name
|
32
30
|
##break if @option.all.nil? && index >= 2 # display only 3, unless all
|
33
31
|
end
|
@@ -36,15 +34,15 @@ module Rudy
|
|
36
34
|
end
|
37
35
|
|
38
36
|
def disks_wash
|
39
|
-
|
40
|
-
dirt = (rdisk.list || [])#.select { |d| d.available? }
|
37
|
+
dirt = (Rudy::Disks.list || []).select { |d| !d.volume_exists? }
|
41
38
|
if dirt.empty?
|
42
|
-
puts "Nothing to wash in #{
|
39
|
+
puts "Nothing to wash in #{current_machine_group}"
|
43
40
|
return
|
44
41
|
end
|
45
42
|
|
46
43
|
puts "The following disk metadata will be deleted:"
|
47
44
|
puts dirt.collect {|d| d.name }
|
45
|
+
|
48
46
|
execute_check(:medium)
|
49
47
|
|
50
48
|
dirt.each do |d|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Rudy::CLI
|
4
|
+
|
5
|
+
# A base for all Drydock executables (bin/rudy etc...).
|
6
|
+
class Base
|
7
|
+
extend Drydock
|
8
|
+
|
9
|
+
debug :off
|
10
|
+
|
11
|
+
before do |obj|
|
12
|
+
# Don't print Rudy header unless requested to
|
13
|
+
obj.global.print_header = false if (obj.global.verbose == 0)
|
14
|
+
@start = Time.now
|
15
|
+
end
|
16
|
+
|
17
|
+
after do |obj|
|
18
|
+
if obj.global.verbose > 0
|
19
|
+
puts
|
20
|
+
@elapsed = Time.now - @start
|
21
|
+
puts "Elapsed: %.2f seconds" % @elapsed.to_f if @elapsed > 0.1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# These globals are used by all bin/ executables
|
26
|
+
global :A, :accesskey, String, "AWS Access Key"
|
27
|
+
global :S, :secretkey, String, "AWS Secret Access Key"
|
28
|
+
global :R, :region, String, "Amazon service region (e.g. #{Rudy::DEFAULT_REGION})"
|
29
|
+
global :z, :zone, String, "Amazon Availability zone (e.g. #{Rudy::DEFAULT_ZONE})"
|
30
|
+
global :u, :user, String, "Provide a username (ie: #{Rudy.sysinfo.user})"
|
31
|
+
global :l, :localhost, String, "Provide a localhost (e.g. #{Rudy.sysinfo.hostname})"
|
32
|
+
global :i, :identity, String, "Path to SSH identity (private key) for RSA or DSA authentication"
|
33
|
+
global :k, :pkey, String, "AWS Private Encryption Key (pk-****.pem)"
|
34
|
+
global :c, :cert, String, "AWS Private Certificate (cert-****.pem)"
|
35
|
+
global :f, :format, String, "Output format"
|
36
|
+
global :n, :nocolor, "Disable output colors"
|
37
|
+
global :Y, :auto, "Skip interactive confirmation"
|
38
|
+
global :q, :quiet, "Run with less output"
|
39
|
+
global :O, :offline, "Be cool about the internet being down"
|
40
|
+
global :C, :config, String, "Specify another configuration file to read (e.g. #{Rudy::CONFIG_FILE})" do |val|
|
41
|
+
@configs ||= []
|
42
|
+
@configs << val
|
43
|
+
end
|
44
|
+
global :v, :verbose, "Increase verbosity of output (e.g. -v or -vv or -vvv)" do
|
45
|
+
@verbose ||= 0
|
46
|
+
@verbose += 1
|
47
|
+
end
|
48
|
+
global :V, :version, "Display version number" do
|
49
|
+
puts "Rudy version: #{Rudy::VERSION}"
|
50
|
+
exit 0
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/rudy/cli/machines.rb
CHANGED
@@ -11,29 +11,22 @@ module Rudy
|
|
11
11
|
# When all is specified we want to find machines in every
|
12
12
|
# environment and role to we remove these attributes from
|
13
13
|
# the select.
|
14
|
-
|
15
|
-
less =
|
14
|
+
fields, less = {}, []
|
15
|
+
less = Rudy::Metadata::COMMON_FIELDS if @option.all
|
16
16
|
|
17
|
-
|
18
|
-
mlist = rmach.list(more, less) || []
|
17
|
+
mlist = Rudy::Machines.list(fields, less) || []
|
19
18
|
if mlist.empty?
|
20
|
-
|
21
|
-
puts "No machines running"
|
22
|
-
else
|
23
|
-
puts "No machines running in #{current_machine_group}"
|
24
|
-
puts "Try: rudy machines --all"
|
25
|
-
end
|
19
|
+
raise( NoMachines, @option.all ? nil : current_group_name)
|
26
20
|
end
|
27
21
|
mlist.each do |m|
|
28
|
-
puts @@global.verbose > 0 ? m.
|
22
|
+
puts @@global.verbose > 0 ? m.to_yaml : "#{m.name}: #{m.dns_public}"
|
29
23
|
end
|
30
24
|
end
|
31
25
|
|
32
26
|
def machines_wash
|
33
|
-
|
34
|
-
dirt = (rmach.list || []).select { |m| !m.running? }
|
27
|
+
dirt = (Rudy::Machines.list || []).select { |m| !m.instance_running? }
|
35
28
|
if dirt.empty?
|
36
|
-
puts "Nothing to wash in #{
|
29
|
+
puts "Nothing to wash in #{current_machine_group}"
|
37
30
|
return
|
38
31
|
end
|
39
32
|
|
@@ -47,70 +40,274 @@ module Rudy
|
|
47
40
|
|
48
41
|
end
|
49
42
|
|
43
|
+
def associate_machines_valid?
|
44
|
+
@mlist = Rudy::Machines.list || []
|
45
|
+
@alist = Rudy::AWS::EC2::Addresses.list || []
|
46
|
+
@alist_used = @alist.select { |a| a.associated? }
|
47
|
+
@alist_unused = @alist.select { |a| !a.associated? }
|
48
|
+
@alist_unused.collect! { |a| a.ipaddress }
|
49
|
+
@alist_instids = @alist_used.collect { |a| a.instid }
|
50
|
+
@mlist_static = @mlist.select do |m|
|
51
|
+
@alist_instids.member?(m.instid)
|
52
|
+
end
|
53
|
+
|
54
|
+
unless @@global.force
|
55
|
+
unless @mlist_static.empty?
|
56
|
+
msg = "Some machines already have static IP addresses: #{$/}"
|
57
|
+
msg << @mlist_static.collect { |m| "#{m.name}: #{m.dns_public}" }.join($/)
|
58
|
+
raise Rudy::Error, msg
|
59
|
+
end
|
60
|
+
|
61
|
+
if !@argv.empty? && @mlist.size > @argv.size
|
62
|
+
msg = "You supplied #{@argv.size} addresses for #{@mlist.size} "
|
63
|
+
msg << "machines. Try: rudy --force machines -S #{@argv.join(' ')}"
|
64
|
+
raise Rudy::Error, msg
|
65
|
+
end
|
66
|
+
|
67
|
+
if @alist_unused.size > 0 && @alist_unused.size < @mlist.size
|
68
|
+
msg = "There are only #{@alist_unused.size} available addresses for "
|
69
|
+
msg << "#{@mlist.size} machines. Try: rudy --force machines -S #{@argv.join(' ')}"
|
70
|
+
raise Rudy::Error, msg
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
@argv.each do |address|
|
75
|
+
unless Rudy::AWS::EC2::Addresses.exists?(address)
|
76
|
+
raise "#{address} is not allocated to you"
|
77
|
+
end
|
78
|
+
if Rudy::AWS::EC2::Addresses.associated?(address)
|
79
|
+
raise "#{address} is already associated!"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
@alist_unused = @argv unless @argv.empty?
|
84
|
+
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
def associate_machines
|
89
|
+
|
90
|
+
puts "Assigning static IP addresses for:"
|
91
|
+
puts @mlist.collect { |m| m.name }
|
92
|
+
|
93
|
+
execute_check(:medium)
|
94
|
+
|
95
|
+
@mlist.each do |m|
|
96
|
+
next if @mlist_static.member?(m)
|
97
|
+
address = @alist_unused.shift
|
98
|
+
address ||= Rudy::AWS::EC2::Addresses.create.ipaddress
|
99
|
+
puts "Associating #{address} to #{m.name} (#{m.instid})"
|
100
|
+
Rudy::AWS::EC2::Addresses.associate(address, m.instid)
|
101
|
+
sleep 2
|
102
|
+
m.refresh!
|
103
|
+
end
|
104
|
+
|
105
|
+
@alist = Rudy::AWS::EC2::Addresses.list || []
|
106
|
+
@alist_used = @alist.select { |a| a.associated? }
|
107
|
+
@alist_instids = @alist_used.collect { |a| a.instid }
|
108
|
+
@mlist_static = @mlist.select do |m|
|
109
|
+
@alist_instids.member?(m.instid)
|
110
|
+
end
|
111
|
+
|
112
|
+
unless @mlist_static.empty?
|
113
|
+
@mlist_static.each do |m|
|
114
|
+
puts "%s: %s" % [m.name, m.dns_public]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def disassociate_machines_valid?
|
121
|
+
@mlist = Rudy::Machines.list || []
|
122
|
+
@alist = Rudy::AWS::EC2::Addresses.list || []
|
123
|
+
@alist_used = @alist.select { |a| a.associated? }
|
124
|
+
@alist_instids = @alist_used.collect { |a| a.instid }
|
125
|
+
@mlist_static = @mlist.select do |m|
|
126
|
+
@alist_instids.member?(m.instid)
|
127
|
+
end
|
128
|
+
raise NoMachines, current_group_name if @mlist.empty?
|
129
|
+
true
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def disassociate_machines
|
134
|
+
if @mlist_static.empty?
|
135
|
+
puts "No machines in #{current_group_name} have static IP addresses"
|
136
|
+
else
|
137
|
+
puts "The following machines will be updated:"
|
138
|
+
puts @mlist_static.collect { |m| m.name }
|
139
|
+
puts "NOTE: Unassigned IP addresses are not removed from your account"
|
140
|
+
execute_check(:medium)
|
141
|
+
@mlist_static.each do |m|
|
142
|
+
address = Resolv.getaddress m.dns_public
|
143
|
+
puts "Disassociating #{address} from #{m.name} (#{m.instid})"
|
144
|
+
Rudy::AWS::EC2::Addresses.disassociate(address)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def update_machines
|
150
|
+
fields, less = {}, []
|
151
|
+
less = Rudy::Metadata::COMMON_FIELDS if @option.all
|
152
|
+
mlist = Rudy::Machines.list(fields, less) || []
|
153
|
+
rset = Rye::Set.new(current_group_name, :parallel => @@global.parallel, :user => 'root')
|
154
|
+
os = current_machine_os
|
155
|
+
mlist.each do |m|
|
156
|
+
m.refresh!
|
157
|
+
rbox = Rye::Box.new(m.dns_public, :user => 'root')
|
158
|
+
rbox.add_key user_keypairpath('root')
|
159
|
+
rbox.nickname = m.name
|
160
|
+
rbox.stash = m
|
161
|
+
rset.add_boxes rbox
|
162
|
+
puts "Updating metadata"
|
163
|
+
if m.os.to_s != os.to_s
|
164
|
+
puts "os: #{os}"
|
165
|
+
m.os = os
|
166
|
+
end
|
167
|
+
m.save :replace
|
168
|
+
end
|
169
|
+
|
170
|
+
unless os.to_s == 'win32'
|
171
|
+
puts "Updating hostnames for #{current_group_name}"
|
172
|
+
Rudy::Routines::Handlers::Host.set_hostname rset
|
173
|
+
puts rset.hostname.flatten
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
def available_machines
|
179
|
+
fields, less = {}, []
|
180
|
+
less = Rudy::Metadata::COMMON_FIELDS if @option.all
|
181
|
+
mlist = Rudy::Machines.list(fields, less) || []
|
182
|
+
mlist.each do |m|
|
183
|
+
print "#{m.name}: "
|
184
|
+
m.refresh!
|
185
|
+
Rudy::Utils.waiter(2, 60, STDOUT, nil, 0) {
|
186
|
+
Rudy::Utils.service_available?(m.dns_public, 22)
|
187
|
+
}
|
188
|
+
available = Rudy::Utils.service_available?(m.dns_public, 22)
|
189
|
+
puts available ? 'up' : 'down'
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
50
194
|
|
51
195
|
def ssh
|
52
|
-
# TODO: Give this
|
53
|
-
pkey =
|
196
|
+
# TODO: Give this method a good look over
|
197
|
+
pkey = current_user_keypairpath
|
54
198
|
unless pkey
|
55
|
-
puts "No private key configured for #{
|
199
|
+
puts "No private key configured for #{current_machine_user} in #{current_machine_group}"
|
56
200
|
end
|
57
201
|
|
58
|
-
# Options to be sent to
|
59
|
-
|
202
|
+
# Options to be sent to Rye::Box
|
203
|
+
rye_opts = { :user => current_machine_user, :debug => nil }
|
60
204
|
if pkey
|
61
205
|
raise "Cannot find file #{pkey}" unless File.exists?(pkey)
|
62
|
-
|
63
|
-
|
206
|
+
if Rudy.sysinfo.os != :win32 && File.stat(pkey).mode != 33152
|
207
|
+
raise InsecureKeyPermissions, pkey
|
208
|
+
end
|
209
|
+
rye_opts[:keys] = pkey
|
64
210
|
end
|
65
|
-
|
66
|
-
|
211
|
+
|
67
212
|
# The user specified a command to run. We won't create an interactive
|
68
213
|
# session so we need to prepare the command and its arguments
|
69
214
|
if @argv.first
|
70
215
|
command, command_args = @argv.shift, @argv || []
|
71
|
-
|
216
|
+
Rudy::Huxtable.ld "COMMAND: #{command} #{command_args.join(' ')}" if @@global.verbose > 1
|
72
217
|
|
73
218
|
# otherwise, we'll open an ssh session or print command
|
74
219
|
else
|
75
220
|
command, command_args = :interactive_ssh, @option.print.nil?
|
76
221
|
end
|
77
|
-
|
78
|
-
|
222
|
+
|
223
|
+
if command == :interactive_ssh && @global.parallel
|
224
|
+
raise "Cannot run interactive sessions in parallel"
|
225
|
+
end
|
226
|
+
|
79
227
|
checked = false
|
80
|
-
|
81
|
-
lt = rudy.list
|
228
|
+
lt = Rudy::Machines.list
|
82
229
|
unless lt
|
83
|
-
puts "No machines running in #{
|
84
|
-
|
230
|
+
puts "No machines running in #{current_machine_group}"
|
231
|
+
return
|
85
232
|
end
|
233
|
+
|
234
|
+
rset = Rye::Set.new(current_machine_group, :parallel => @global.parallel)
|
86
235
|
lt.each do |machine|
|
87
|
-
machine.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
236
|
+
machine.refresh! # make sure we have the latest DNS info
|
237
|
+
rbox = Rye::Box.new(machine.dns_public, rye_opts)
|
238
|
+
rbox.nickname = machine.name
|
239
|
+
if command == :interactive_ssh
|
240
|
+
# Print header
|
241
|
+
if @@global.quiet
|
242
|
+
print "You are #{rye_opts[:user].to_s.bright}. " if !checked # only the 1st
|
243
|
+
else
|
244
|
+
puts machine_separator(machine.name, machine.instid)
|
245
|
+
puts "Connecting #{rye_opts[:user].to_s.bright}@#{machine.dns_public} "
|
246
|
+
puts
|
247
|
+
end
|
94
248
|
else
|
95
|
-
|
96
|
-
|
97
|
-
|
249
|
+
unless @global.parallel
|
250
|
+
rbox.pre_command_hook do |cmd,user,host,nickname|
|
251
|
+
print_command user, nickname, cmd
|
252
|
+
end
|
253
|
+
end
|
254
|
+
rbox.post_command_hook do |ret|
|
255
|
+
print_response ret
|
256
|
+
end
|
98
257
|
end
|
99
258
|
|
100
259
|
# Make sure we want to run this command on all instances
|
101
260
|
if !checked && command != :interactive_ssh
|
102
|
-
execute_check(:low) if
|
261
|
+
execute_check(:low) if rye_opts[:user] == "root"
|
103
262
|
checked = true
|
104
263
|
end
|
105
264
|
|
106
|
-
# Open the connection and run the command
|
107
|
-
|
108
|
-
|
109
|
-
|
265
|
+
# Open the connection and run the command
|
266
|
+
if command == :interactive_ssh
|
267
|
+
rbox.send(command, command_args)
|
268
|
+
else
|
269
|
+
rset.add_box rbox
|
270
|
+
end
|
110
271
|
end
|
272
|
+
|
273
|
+
rset.send(command, command_args) unless command == :interactive_ssh
|
274
|
+
|
111
275
|
end
|
112
276
|
|
277
|
+
|
278
|
+
private
|
279
|
+
# Returns a formatted string for printing command info
|
280
|
+
def print_command(user, host, cmd)
|
281
|
+
#return if @@global.parallel
|
282
|
+
cmd ||= ""
|
283
|
+
cmd, user = cmd.to_s, user.to_s
|
284
|
+
prompt = user == "root" ? "#" : "$"
|
285
|
+
li ("%s@%s%s %s" % [user, host, prompt, cmd.bright])
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
def print_response(rap)
|
290
|
+
# Non zero exit codes raise exceptions so
|
291
|
+
# the erorrs have already been handled.
|
292
|
+
return if rap.exit_code != 0
|
113
293
|
|
294
|
+
if @@global.parallel
|
295
|
+
cmd, user = cmd.to_s, user.to_s
|
296
|
+
prompt = user == "root" ? "#" : "$"
|
297
|
+
li "%s@%s%s %s%s%s" % [rap.box.user, rap.box.nickname, prompt, rap.cmd.bright, $/, rap.stdout.inspect]
|
298
|
+
unless rap.stderr.empty?
|
299
|
+
le "#{rap.box.nickname}: " << rap.stderr.join("#{rap.box.nickname}: ")
|
300
|
+
end
|
301
|
+
else
|
302
|
+
li ' ' << rap.stdout.join("#{$/} ") if !rap.stdout.empty?
|
303
|
+
colour = rap.exit_code != 0 ? :red : :normal
|
304
|
+
unless rap.stderr.empty?
|
305
|
+
le (" STDERR " << '-'*38).color(colour).bright
|
306
|
+
le " " << rap.stderr.join("#{$/} ").color(colour)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
114
311
|
end
|
115
312
|
end
|
116
313
|
end
|