awsome 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/awsome ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'awsome'
4
+ require 'optparse'
5
+
6
+ requirements_file = 'requirements.yml'
7
+ OptionParser.new do |opts|
8
+ opts.banner = 'Usage: awsome [options]'
9
+ opts.on('-r', '--requirements [FILE]', 'Use a requirements file from another location (default is ./requirements.yml)') do |opt|
10
+ requirements_file = opt
11
+ end
12
+ opts.on('-v', '--verbose', 'Print commands as they are executed') do |opt|
13
+ Awsome.config.verbose = true
14
+ end
15
+ opts.on('-d', '--debug', 'Run ec2 commands with --debug') do |opt|
16
+ Awsome.config.debug = true
17
+ end
18
+ opts.on('-s', '--stacks', 'Print out full stack traces when commands are executed') do |opt|
19
+ Awsome.config.stacks = true
20
+ end
21
+ end.parse!
22
+
23
+ instances = Awsome::Ec2.describe_instances('instance-state-name' => 'running')
24
+ requirements = Awsome::Requirements.from_yaml_file(requirements_file)
25
+ matchmaker = Awsome::Matchmaker.new(instances, requirements)
26
+ executor = Awsome::Executor.new(matchmaker.matches)
27
+
28
+ executor.execute
data/lib/awsome.rb ADDED
@@ -0,0 +1,81 @@
1
+ module Awsome
2
+ def self.config
3
+ @@config ||= Config.new
4
+ end
5
+
6
+ def self.execute(command, options={})
7
+ command = command.join(' ') if command.is_a?(Array)
8
+ if config.verbose
9
+ puts
10
+ puts command
11
+ puts '='*command.length
12
+ end
13
+ if options[:system]
14
+ result = system(command)
15
+ else
16
+ result = `#{command}`
17
+ result = options[:preprocess].call(result) if options[:preprocess]
18
+ result = map_table(result, options)
19
+ end
20
+ ensure
21
+ if config.verbose
22
+ case result
23
+ when String then puts result
24
+ else ap result
25
+ end
26
+ end
27
+ if config.stacks
28
+ ap Kernel.caller
29
+ end
30
+ end
31
+
32
+ def self.map_table(table, options)
33
+ return table unless options[:columns]
34
+ rows = table.split("\n")
35
+ rows.select! { |row| row =~ options[:filter] } if options[:filter]
36
+ rows.collect do |row|
37
+ properties = {}
38
+ values = options[:delimiter] ? row.split(options[:delimiter]) : row.split
39
+ values.each_with_index { |value, index|
40
+ field = options[:columns][index]
41
+ properties[field] = value
42
+ }
43
+ properties
44
+ end
45
+ end
46
+
47
+ def self.wait_until(opts={}, &block)
48
+ retries = opts[:retries] || 5
49
+ interval = opts[:interval] || 5
50
+ while !yield && retries > 0
51
+ puts "block returned false (#{retries} more retries)..." if Awsome.config.verbose
52
+ sleep interval
53
+ retries -= 1
54
+ end
55
+ end
56
+
57
+ class Config
58
+ attr_accessor :region, :url, :aws_access_key, :aws_secret_key, :connection_timeout,
59
+ :request_timeout, :verbose, :show_empty_fields, :debug, :show_request, :stacks
60
+
61
+ def initialize
62
+ @region = ENV['REGION']
63
+ @url = ENV['EC2_URL']
64
+ @aws_access_key = ENV['AWS_ACCESS_KEY']
65
+ @aws_secret_key = ENV['AWS_SECRET_KEY']
66
+ @show_empty_fields = true
67
+ end
68
+ end
69
+ end
70
+
71
+ require 'set'
72
+ require 'awesome_print'
73
+ require 'awsome/ec2.rb'
74
+ require 'awsome/elb.rb'
75
+ require 'awsome/ssh.rb'
76
+ require 'awsome/debian.rb'
77
+ require 'awsome/requirements.rb'
78
+ require 'awsome/executor.rb'
79
+ require 'awsome/matchmaker.rb'
80
+ require 'awsome/requirements_options.rb'
81
+ require 'awsome/instance_requirement.rb'
@@ -0,0 +1,36 @@
1
+ module Awsome
2
+ module Debian
3
+ def self.describe_debian_packages(hostname)
4
+ if Awsome::Ssh.scp("#{hostname}:/home/ubuntu/packages.csv", './packages.csv')
5
+ File.open('./packages.csv', 'r').read.strip.split(',')
6
+ else
7
+ []
8
+ end
9
+ end
10
+
11
+ def self.remove_debian_packages(hostname, *packages)
12
+ installed = describe_debian_packages(hostname)
13
+ remaining = installed.to_set - packages.to_set
14
+
15
+ return if packages.empty?
16
+
17
+ Awsome::Ssh.ssh hostname, "sudo apt-get update"
18
+ Awsome::Ssh.ssh hostname, "sudo apt-get remove -y --force-yes #{packages.join(' ')}"
19
+ Awsome::Ssh.ssh hostname, "echo #{remaining.to_a.join(',')} > ~/packages.csv"
20
+ end
21
+
22
+ def self.install_debian_packages(hostname, *packages)
23
+ installed = describe_debian_packages(hostname)
24
+ remaining = installed.to_set + packages.to_set
25
+
26
+ Awsome::Ssh.ssh hostname, "sudo apt-get update"
27
+
28
+ if packages.empty?
29
+ Awsome::Ssh.ssh hostname, "sudo apt-get upgrade"
30
+ else
31
+ Awsome::Ssh.ssh hostname, "sudo apt-get install -y --force-yes #{packages.join(' ')}"
32
+ Awsome::Ssh.ssh hostname, "echo #{remaining.to_a.join(',')} > ~/packages.csv"
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/awsome/ec2.rb ADDED
@@ -0,0 +1,109 @@
1
+ module Awsome
2
+ module Ec2
3
+ def self.config
4
+ Awsome.config
5
+ end
6
+
7
+ def self.command(*cmd)
8
+ args = cmd.last.is_a?(Hash) && cmd.pop
9
+ options = cmd
10
+ options << "--region #{config.region}"
11
+ options << "--url #{config.url}"
12
+ options << "--aws-access-key #{config.aws_access_key}"
13
+ options << "--aws-secret-key #{config.aws_secret_key}"
14
+ options << "--connection-timeout #{config.connection_timeout}" if config.connection_timeout
15
+ options << "--request-timeout #{config.request_timeout}" if config.request_timeout
16
+ options << "--verbose" if config.verbose
17
+ options << "--show-empty-fields" if config.show_empty_fields
18
+ options << "--debug" if config.debug
19
+ args && args.each { |k,v| options << "--#{k} #{v}" }
20
+ options.join(' ')
21
+ end
22
+
23
+ def self.map_table(*args)
24
+ Awsome.map_table(*args)
25
+ end
26
+
27
+ @@run_instance_fields = %w(
28
+ instance_identifier
29
+ instance_id
30
+ ami_id
31
+ state
32
+ key
33
+ ami_launch_index
34
+ product_code
35
+ instance_type
36
+ instance_launch_time
37
+ availability_zone
38
+ )
39
+
40
+ def self.run_instance(properties)
41
+ cmd = command('ec2-run-instances', properties['ami_id'],
42
+ :group => properties['security_group_ids'],
43
+ :key => properties['key'],
44
+ 'instance-type'.to_sym => properties['instance_type'],
45
+ 'availability-zone'.to_sym => properties['availability_zone']
46
+ )
47
+ Awsome::Ec2::Instance.new(Awsome.execute(cmd, columns: @@run_instance_fields, filter: /^INSTANCE/).first)
48
+ end
49
+
50
+ @@describe_instance_fields = %w(
51
+ reservation_identifier
52
+ reservation_id
53
+ aws_account_id
54
+ security_group_ids
55
+ instance_identifier
56
+ instance_id
57
+ ami_id
58
+ public_dns_name
59
+ private_dns_name
60
+ state
61
+ key
62
+ ami_launch_index
63
+ product_codes
64
+ instance_type
65
+ instance_launch_time
66
+ availability_zone
67
+ )
68
+
69
+ def self.describe_instances(filters={})
70
+ cmd = [Awsome::Ec2.command('ec2-describe-instances')]
71
+ cmd += filters.collect { |k,v| "--filter \"#{k}=#{v}\"" }
72
+ preprocess = Proc.new { |text| text.gsub("\nINSTANCE", " INSTANCE") }
73
+ properties = Awsome.execute(cmd, columns: @@describe_instance_fields, filter: /^RESERVATION/, preprocess: preprocess)
74
+ properties.collect { |p| Awsome::Ec2::Instance.new(p) }
75
+ end
76
+
77
+ @@describe_volumes_fields = %w(
78
+ attachment_identifier
79
+ volume_id
80
+ instance_id
81
+ device
82
+ state
83
+ date
84
+ )
85
+
86
+ def self.describe_volumes(filters={})
87
+ cmd = [Awsome::Ec2.command('ec2-describe-volumes')]
88
+ cmd += filters.collect { |k,v| "--filter \"#{k}=#{v}\"" }
89
+ Awsome.execute(cmd, columns: @@describe_volumes_fields, filter: /^ATTACHMENT/)
90
+ end
91
+
92
+ def self.detach_volume(volume_id)
93
+ cmd = Awsome::Ec2.command('ec2-detach-volume', volume_id)
94
+ Awsome.execute(cmd)
95
+ end
96
+
97
+ def self.attach_volume(volume_id, instance_id, device)
98
+ cmd = Awsome::Ec2.command('ec2-attach-volume', volume_id, instance: instance_id, device: device)
99
+ Awsome.execute(cmd)
100
+ end
101
+
102
+ def self.terminate_instances(*instance_ids)
103
+ cmd = Awsome::Ec2.command("ec2-terminate-instances #{instance_ids.join(' ')}")
104
+ Awsome.execute(cmd)
105
+ end
106
+ end
107
+ end
108
+
109
+ require 'awsome/ec2/instance.rb'
@@ -0,0 +1,76 @@
1
+ module Awsome
2
+ module Ec2
3
+ class Instance
4
+ attr_reader :properties
5
+
6
+ def initialize(property_hash)
7
+ raise 'properties must be a hash' unless property_hash.is_a?(Hash)
8
+ @properties = property_hash.clone
9
+ end
10
+
11
+ def packages
12
+ Awsome::Debian.describe_debian_packages(@properties['public_dns_name']).to_set
13
+ end
14
+
15
+ def volumes
16
+ Awsome::Ec2.describe_volumes('attachment.instance-id' => @properties['instance_id']).collect do |p|
17
+ p['volume_id']
18
+ end.to_set
19
+ end
20
+
21
+ def wait_until_running!
22
+ Awsome.wait_until(interval: 10) do
23
+ reload!
24
+ @properties['state'] =~ /^running/
25
+ end
26
+ end
27
+
28
+ def wait_for_ssh!
29
+ Awsome.wait_until(interval: 10) { has_ssh? }
30
+ end
31
+
32
+ def reattach_volumes(*volumes)
33
+ volumes.each do |info|
34
+ Awsome::Ec2.detach_volume(info['id'])
35
+ Awsome::Ec2.attach_volume(info['id'], @properties['instance_id'], info['device'])
36
+ end
37
+ end
38
+
39
+ def deregister_from_elbs
40
+ elbs.each { |elb| elb.deregister(@properties['instance_id']) }
41
+ end
42
+
43
+ def register_with_elbs(*load_balancer_names)
44
+ Awsome::Elb.describe_lbs(*load_balancer_names).each { |elb| elb.register(@properties['instance_id']) }
45
+ end
46
+
47
+ def remove_packages(*packages)
48
+ Awsome::Debian.remove_debian_packages(@properties['public_dns_name'], *packages)
49
+ end
50
+
51
+ def install_packages(*packages)
52
+ Awsome::Debian.install_debian_packages(@properties['public_dns_name'], *packages)
53
+ end
54
+
55
+ def terminate
56
+ Awsome::Ec2.terminate_instances(@properties['instance_id'])
57
+ end
58
+
59
+ private
60
+ def reload!
61
+ instance = Awsome::Ec2.describe_instances('instance-id' => @properties['instance_id']).first
62
+ raise "instance #{@properties['instance_id']} not found" if instance.nil?
63
+ @properties = instance.properties.clone
64
+ end
65
+
66
+ def has_ssh?
67
+ Awsome::Ssh.has_ssh?(@properties['public_dns_name'])
68
+ end
69
+
70
+ def elbs
71
+ Awsome::Elb.describe_lbs.select { |elb| elb.instances.include?(@properties['instance_id']) }
72
+ end
73
+
74
+ end
75
+ end
76
+ end
data/lib/awsome/elb.rb ADDED
@@ -0,0 +1,66 @@
1
+ module Awsome
2
+ module Elb
3
+ @@delimiter = " OH YEAH BANANAS "
4
+
5
+ def self.config
6
+ Awsome.config
7
+ end
8
+
9
+ def self.command(*cmd)
10
+ args = cmd.last.is_a?(Hash) && cmd.pop
11
+ options = cmd
12
+ options << "--region #{config.region}"
13
+ # options << "--url #{config.url}" # explicitly setting the url this way breaks the elb tools
14
+ options << "--access-key-id #{config.aws_access_key}"
15
+ options << "--secret-key #{config.aws_secret_key}"
16
+ options << "--show-long"
17
+ options << "--delimiter \"#{@@delimiter}\""
18
+ options << "--show-request" if config.show_request
19
+ options << "--show-empty-fields" if config.show_empty_fields
20
+ options << "--connection-timeout #{config.connection_timeout}" if config.connection_timeout
21
+ args && args.each { |k,v| options << "--#{k} #{v}" }
22
+ options.join(' ')
23
+ end
24
+
25
+ @@describe_lbs_columns = %w(
26
+ identifier
27
+ name
28
+ dns_name
29
+ canonical_hosted_zone_name
30
+ canonical_hosted_zone_name_id
31
+ health_check
32
+ availability_zones
33
+ subnets
34
+ vpc_id
35
+ instance_ids
36
+ listener_descriptions
37
+ backend_server_descriptions
38
+ app_cookie_stickiness_policies
39
+ lb_cookie_stickiness_policies
40
+ other_policies
41
+ source_security_group
42
+ security_groups
43
+ created_time
44
+ scheme
45
+ pagination_marker
46
+ )
47
+
48
+ def self.describe_lbs(*load_balancer_names)
49
+ cmd = Awsome::Elb.command("elb-describe-lbs #{load_balancer_names.join(' ')}")
50
+ properties = Awsome.execute(cmd, columns: @@describe_lbs_columns, delimiter: @@delimiter)
51
+ properties.collect { |p| Awsome::Elb::LoadBalancer.new(p) }
52
+ end
53
+
54
+ def self.deregister_instance_from_lb(load_balancer_name, instance_id)
55
+ cmd = Awsome::Elb.command('elb-deregister-instances-from-lb', load_balancer_name, instances: instance_id, delimiter: @@delimiter)
56
+ Awsome.execute(cmd)
57
+ end
58
+
59
+ def self.register_instance_with_lb(load_balancer_name, instance_id)
60
+ cmd = Awsome::Elb.command('elb-register-instances-with-lb', load_balancer_name, instances: instance_id, delimiter: @@delimiter)
61
+ Awsome.execute(cmd)
62
+ end
63
+ end
64
+ end
65
+
66
+ require 'awsome/elb/load_balancer.rb'
@@ -0,0 +1,30 @@
1
+ module Awsome
2
+ module Elb
3
+ class LoadBalancer
4
+ attr_reader :properties
5
+
6
+ def initialize(property_hash)
7
+ @properties = property_hash.clone
8
+ end
9
+
10
+ def instances
11
+ @properties['instance_ids'].gsub('"', '').split(',').collect(&:strip).to_set
12
+ end
13
+
14
+ def deregister(instance_id)
15
+ Awsome::Elb.deregister_instance_from_lb(@properties['name'], instance_id)
16
+ end
17
+
18
+ def register(instance_id)
19
+ Awsome::Elb.register_instance_with_lb(@properties['name'], instance_id)
20
+ end
21
+
22
+ private
23
+ def reload!
24
+ elb = Awsome::Elb.describe_lbs(@properties['name']).first
25
+ raise "elb #{@properties['name']} not found" if elb.nil?
26
+ @properties = elb.properties.clone
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,66 @@
1
+ module Awsome
2
+ class Executor
3
+ def initialize(matches)
4
+ @matches = matches
5
+ end
6
+
7
+ def execute
8
+ @matches.each { |s, m| execute_match(s, m) }
9
+ end
10
+
11
+ private
12
+
13
+ def execute_match(signature, match)
14
+ @i_pool = match[:i_pool]
15
+ @r_pool = match[:r_pool]
16
+
17
+ puts "instance pool:"
18
+ ap @i_pool
19
+
20
+ puts "requirement pool:"
21
+ ap @r_pool
22
+
23
+ run
24
+ wait_for_ssh
25
+ reattach_volumes
26
+ deploy
27
+ terminate
28
+ end
29
+
30
+ def run
31
+ @i_pool.each_with_index do |instance, i|
32
+ @i_pool[i] = Awsome::Ec2.run_instance(@r_pool[i].properties) if instance.nil?
33
+ end
34
+ end
35
+
36
+ def wait_for_ssh
37
+ @i_pool.each do |i|
38
+ i.wait_until_running!
39
+ i.wait_for_ssh!
40
+ end
41
+ end
42
+
43
+ def reattach_volumes
44
+ @i_pool.each_with_index do |instance, i|
45
+ instance.reattach_volumes(*@r_pool[i].volumes_to_attach(instance))
46
+ end
47
+ end
48
+
49
+ def deploy
50
+ @i_pool.each_with_index do |instance, i|
51
+ instance.deregister_from_elbs
52
+ instance.remove_packages(*@r_pool[i].packages_to_remove(instance))
53
+ instance.install_packages(*@r_pool[i].packages_to_install(instance))
54
+ instance.register_with_elbs(*@r_pool[i].elbs)
55
+ end
56
+ end
57
+
58
+ def terminate
59
+ @i_pool.each_with_index do |instance, i|
60
+ next if i < @r_pool.length
61
+ instance.deregister_from_elbs
62
+ instance.terminate
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,56 @@
1
+ module Awsome
2
+ class InstanceRequirement
3
+
4
+ attr_reader :properties
5
+
6
+ def initialize(properties, options)
7
+ @properties = properties.clone
8
+ @options = options
9
+ end
10
+
11
+ def elbs
12
+ @properties['elbs']
13
+ end
14
+
15
+ def volumes_to_attach(instance)
16
+ (volumes - volumes_attached_to(instance)).collect { |v| @options.find_volume(v) }
17
+ end
18
+
19
+ def volumes_to_detach(instance)
20
+ (volumes_attached_to(instance) - volumes).collect { |v| @options.find_volume(v) }
21
+ end
22
+
23
+ def volume_change_count(instance)
24
+ volumes_to_attach(instance).size + volumes_to_detach(instance).size
25
+ end
26
+
27
+ def packages_to_install(instance)
28
+ packages - packages_installed_on(instance)
29
+ end
30
+
31
+ def packages_to_remove(instance)
32
+ packages_installed_on(instance) - packages
33
+ end
34
+
35
+ def package_change_count(instance)
36
+ packages_to_install(instance).size + packages_to_remove(instance).size
37
+ end
38
+
39
+ private
40
+ def packages
41
+ @properties['packages'].to_set
42
+ end
43
+
44
+ def volumes
45
+ @options.filter_volume_ids(@properties['volumes'])
46
+ end
47
+
48
+ def packages_installed_on(instance)
49
+ instance ? instance.packages : Set[]
50
+ end
51
+
52
+ def volumes_attached_to(instance)
53
+ instance ? @options.filter_volume_ids(instance.volumes) : Set[]
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,96 @@
1
+ module Awsome
2
+ class Matchmaker
3
+ def initialize(instances, requirements)
4
+ @requirement_pools = requirements.instances.reject do |i|
5
+ requirements.options.except_instance_ids.include?(i.properties['instance_id'])
6
+ end.group_by { |i| signature_for(i) }
7
+
8
+ @instance_pools = instances.reject do |i|
9
+ requirements.options.except_instance_ids.include?(i.properties['instance_id'])
10
+ end.group_by { |i| signature_for(i) }
11
+
12
+ @signatures = @requirement_pools.keys.to_set + @instance_pools.keys.to_set
13
+
14
+ @signatures.each do |s|
15
+ @requirement_pools[s] ||= []
16
+ @instance_pools[s] ||= []
17
+
18
+ # nil indicates new instance will be brought up
19
+ shortage = @requirement_pools[s].size - @instance_pools[s].size
20
+ @instance_pools[s] += [nil]*shortage if shortage > 0
21
+ end
22
+ end
23
+
24
+ @@signature_fields = %w( ami_id key instance_type availability_zone security_group_ids )
25
+
26
+ def signature_for(instance)
27
+ @@signature_fields.collect { |k| instance.properties[k] }.join(',')
28
+ end
29
+
30
+ def matches
31
+ @signatures.reduce({}) { |memo, s| memo.merge(s => best_match(s)) }
32
+ end
33
+
34
+ private
35
+
36
+ def best_match(signature)
37
+ i_pool = @instance_pools[signature]
38
+ r_pool = @requirement_pools[signature]
39
+
40
+ best = nil
41
+
42
+ permute i_pool do |i_pool_perm|
43
+ best = score_match(i_pool_perm, r_pool, best)
44
+ end
45
+
46
+ best
47
+ end
48
+
49
+ def score_match(i_pool, r_pool, best)
50
+ v_delta = 0
51
+ p_delta = 0
52
+
53
+ i_pool.each_with_index do |i, index|
54
+ r = r_pool[index]
55
+ if r
56
+ v_delta += r.volume_change_count(i)
57
+ p_delta += r.package_change_count(i)
58
+ end
59
+ end
60
+
61
+ top_score({
62
+ v_delta: v_delta,
63
+ p_delta: p_delta,
64
+ i_pool: i_pool,
65
+ r_pool: r_pool
66
+ }, best)
67
+ end
68
+
69
+ def top_score(*scores)
70
+ scores.sort_by do |s1, s2|
71
+ case
72
+ when s1.nil? && s2.nil? then 0
73
+ when s2.nil? then -1
74
+ when s1.nil? then 1
75
+ when s1[:v_delta] < s2[:v_delta] then -1
76
+ when s1[:v_delta] > s2[:v_delta] then 1
77
+ when s1[:p_delta] < s2[:p_delta] then -1
78
+ when s1[:p_delta] > s2[:p_delta] then 1
79
+ else 0
80
+ end
81
+ end.first
82
+ end
83
+
84
+ def permute(array, permutation=[], &block)
85
+ if array.empty?
86
+ yield(permutation.clone)
87
+ else
88
+ 0.upto(array.length - 1) do |i|
89
+ permutation << array.slice!(i)
90
+ permute(array, permutation, &block)
91
+ array.insert(i, permutation.pop)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,20 @@
1
+ require 'yaml'
2
+
3
+ module Awsome
4
+ class Requirements
5
+ attr_reader :options
6
+ def initialize(requirements_hash)
7
+ @requirements = requirements_hash.clone
8
+ @options = Awsome::RequirementsOptions.new(@requirements)
9
+ end
10
+ def self.from_yaml_file(filename)
11
+ new(YAML::load(File.open(filename, 'r').read))
12
+ end
13
+ def instances
14
+ @requirements['instances'].collect do |instance_req|
15
+ Awsome::InstanceRequirement.new(instance_req, @options)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,20 @@
1
+ module Awsome
2
+ class RequirementsOptions
3
+ def initialize(requirements)
4
+ @options = (requirements['options'] || {}).clone
5
+ end
6
+ def only_volume_ids
7
+ @options['volumes'].collect { |v| v['id'] }.to_set
8
+ end
9
+ def except_instance_ids
10
+ (@options['except_instance_ids'] || []).to_set
11
+ end
12
+ def filter_volume_ids(ids)
13
+ ids = ids.to_set unless ids.is_a?(Set)
14
+ only_volume_ids.any? ? only_volume_ids & ids : ids
15
+ end
16
+ def find_volume(volume_id)
17
+ @options['volumes'].find { |v| v['id'] == volume_id }
18
+ end
19
+ end
20
+ end
data/lib/awsome/ssh.rb ADDED
@@ -0,0 +1,27 @@
1
+ module Awsome
2
+ module Ssh
3
+ def self.ensure_ssh_env_vars!
4
+ raise 'SSH_KEY environment variable not set' if ENV['SSH_KEY'].nil?
5
+ raise 'SSH_USER environment varibale not set' if ENV['SSH_USER'].nil?
6
+ end
7
+
8
+ def self.ssh(host, *scripts)
9
+ ensure_ssh_env_vars!
10
+ Awsome.execute("ssh -i #{ENV['SSH_KEY']} #{ENV['SSH_USER']}@#{host} \"#{scripts.join(' && ')}\"")
11
+ end
12
+
13
+ def self.scp(from, to)
14
+ ensure_ssh_env_vars!
15
+ if File.exists?(from)
16
+ to = "#{ENV['SSH_USER']}@#{to}"
17
+ else
18
+ from = "#{ENV['SSH_USER']}@#{from}"
19
+ end
20
+ Awsome.execute("scp -i #{ENV['SSH_KEY']} #{from} #{to}", system: true)
21
+ end
22
+
23
+ def self.has_ssh?(host)
24
+ Awsome.execute("nc -zw 2 #{host} 22 < /dev/null", system: true)
25
+ end
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awsome
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sebastian Goodman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: awesome_print
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: AWS library targeted specifically for continuous integration.
31
+ email: sebastian@foodocs.com
32
+ executables:
33
+ - awsome
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/awsome.rb
38
+ - lib/awsome/matchmaker.rb
39
+ - lib/awsome/elb/load_balancer.rb
40
+ - lib/awsome/requirements.rb
41
+ - lib/awsome/ec2.rb
42
+ - lib/awsome/executor.rb
43
+ - lib/awsome/ssh.rb
44
+ - lib/awsome/requirements_options.rb
45
+ - lib/awsome/elb.rb
46
+ - lib/awsome/debian.rb
47
+ - lib/awsome/ec2/instance.rb
48
+ - lib/awsome/instance_requirement.rb
49
+ - bin/awsome
50
+ homepage: http://github.com/0x0539/awsome
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.23
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Intelligently plan automated, incremental deployments.
74
+ test_files: []