jzimmek-ec2 0.0.3

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/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ec2"
8
+ gem.summary = %Q{Management tool for EC2 clouds}
9
+ gem.email = "jan.zimmek@web.de"
10
+ gem.homepage = "http://github.com/jzimmek/ec2"
11
+ gem.authors = ["Jan Zimmek"]
12
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
13
+ end
14
+
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
17
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
data/ec2.gemspec ADDED
@@ -0,0 +1,51 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ec2}
8
+ s.version = "0.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jan Zimmek"]
12
+ s.date = %q{2009-09-14}
13
+ s.email = %q{jan.zimmek@web.de}
14
+ s.extra_rdoc_files = [
15
+ "README"
16
+ ]
17
+ s.files = [
18
+ "README",
19
+ "Rakefile",
20
+ "VERSION",
21
+ "ec2.gemspec",
22
+ "lib/ec2/dsl/cloud.rb",
23
+ "lib/ec2/dsl/group.rb",
24
+ "lib/ec2/dsl/instance.rb",
25
+ "lib/ec2/instance_binding.rb",
26
+ "lib/ec2/manager.rb",
27
+ "lib/ec2/pending.rb",
28
+ "lib/ec2_init.rb",
29
+ "test/ec2_test.rb",
30
+ "test/test_helper.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/jzimmek/ec2}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.4}
36
+ s.summary = %q{Management tool for EC2 clouds}
37
+ s.test_files = [
38
+ "test/ec2_test.rb",
39
+ "test/test_helper.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
47
+ else
48
+ end
49
+ else
50
+ end
51
+ end
@@ -0,0 +1,58 @@
1
+ require 'easy_dsl/container'
2
+ require 'ec2/dsl/group'
3
+
4
+ module Ec2
5
+ module Dsl
6
+ class Cloud < ::EasyDsl::Container
7
+ def initialize(name)
8
+ super(name, nil)
9
+ nested :group, Group
10
+
11
+ attribute :ssh_key_file, :required => true
12
+ attribute :keypair, :inheritable => true
13
+ attribute :security_group, :inheritable => true
14
+ attribute :region, :inheritable => true
15
+ attribute :availability_zone, :inheritable => true
16
+ attribute :userdata, :inheritable => true, :base64 => true, :strip => true
17
+ end
18
+
19
+ def cloud
20
+ self
21
+ end
22
+
23
+ def instances
24
+ @all_group.values.collect{|grp| grp.all_instance.values}.flatten
25
+ end
26
+
27
+ def dump
28
+
29
+ print "hostname".ljust(10)
30
+ print "ami".ljust(15)
31
+ print "ari".ljust(15)
32
+ print "aki".ljust(15)
33
+ print "region".ljust(12)
34
+ print "availability_zone".ljust(18)
35
+ print "keypair".ljust(10)
36
+ print "elastic_ip".ljust(15)
37
+ print "security_group".ljust(15)
38
+ puts ""
39
+
40
+ @all_group.values.each do |grp|
41
+ grp.all_instance.values.each do |i|
42
+ print i.name.ljust(10)
43
+ print i.ami.ljust(15)
44
+ print (i.ari||"").ljust(15)
45
+ print (i.aki||"").ljust(15)
46
+ print i.cloud.region.ljust(12)
47
+ print (i.availability_zone||"").ljust(18)
48
+ print i.keypair.ljust(10)
49
+ print (i.elastic_ip||"").ljust(15)
50
+ print i.security_group.ljust(15)
51
+ puts ""
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,22 @@
1
+ require 'easy_dsl/container'
2
+ require 'ec2/dsl/instance'
3
+
4
+ module Ec2
5
+ module Dsl
6
+ class Group < ::EasyDsl::Container
7
+ def initialize(name, container)
8
+ super
9
+ nested :instance, Instance
10
+
11
+ attribute :ami, :inheritable => true
12
+ attribute :ari, :inheritable => true
13
+ attribute :aki, :inheritable => true
14
+ attribute :keypair, :inheritable => true
15
+ attribute :security_group, :inheritable => true
16
+ attribute :availability_zone, :inheritable => true
17
+ attribute :userdata, :inheritable => true, :base64 => true, :strip => true
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ require 'easy_dsl/container'
2
+
3
+ module Ec2
4
+ module Dsl
5
+ class Instance < ::EasyDsl::Container
6
+ def initialize(name, container)
7
+ super
8
+ attribute :ami, :inheritable => true, :required => true
9
+ attribute :ari, :inheritable => true
10
+ attribute :aki, :inheritable => true
11
+ attribute :keypair, :inheritable => true, :required => true
12
+ attribute :security_group, :inheritable => true, :required => true
13
+ attribute :availability_zone, :inheritable => true
14
+ attribute :userdata, :inheritable => true, :base64 => true, :strip => true
15
+ attribute :elastic_ip, :inheritable => true
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,100 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'net/ssh'
4
+
5
+ module Ec2
6
+ class InstanceBinding
7
+
8
+ attr_reader :hostname
9
+ attr_reader :public_ip
10
+ attr_reader :state
11
+
12
+ def initialize(cloud, ws, id, launch_time, public_dns_name, private_dns_name)
13
+
14
+ @cloud = cloud
15
+ @ws = ws
16
+
17
+ @id = id
18
+ @launch_time = launch_time
19
+ @public_dns_name = public_dns_name
20
+ @private_dns_name = private_dns_name
21
+
22
+ @ssh = Net::SSH.start(@public_dns_name, "root", :keys => [@cloud.ssh_key_file], :paranoid => false)
23
+
24
+ user_data = fetch_from_url("http://169.254.169.254/2009-04-04/user-data")
25
+
26
+ @hostname = user_data.index("Not Found") ? nil : user_data
27
+
28
+ if @hostname
29
+
30
+ Pending.remove(@hostname)
31
+
32
+ @public_ip = fetch_from_url("http://169.254.169.254/latest/meta-data/public-ipv4")
33
+ cfg = fetch_from_file("~/.configuration")
34
+
35
+ @configuration = cfg.blank? ? {} : YAML.load(cfg)
36
+ end
37
+
38
+ end
39
+
40
+ def configured?(name)
41
+ @configuration[name] == true
42
+ end
43
+
44
+ def ensure_configured(name, &block)
45
+ if configured?(name)
46
+ puts "#{name} already configured on instance #{@hostname}"
47
+ else
48
+ puts "#{name} not configured on instance #{@hostname}"
49
+ block.call(@ssh)
50
+ __mark_configured(name)
51
+ end
52
+ end
53
+
54
+ def terminate!
55
+ @ws.terminate_instances(:instance_id => [@id])
56
+ end
57
+
58
+ def __mark_configured(name)
59
+ @configuration[name] = true
60
+ write_to_file("~/.configuration", @configuration.to_yaml)
61
+ puts "#{name} configured on instance #{@hostname}"
62
+ end
63
+
64
+ def valid?
65
+ @cloud.instances.find{|it| it.name == @hostname}
66
+ end
67
+
68
+ def disconnect!
69
+ @ssh.close
70
+ end
71
+
72
+ def ssh(&block)
73
+ block.call(@ssh)
74
+ end
75
+
76
+ def fetch_from_url(url)
77
+ file = "/tmp/.fetch"
78
+ @ssh.exec!("rm #{file}")
79
+ @ssh.exec!("curl -o #{file} #{url}")
80
+ value = @ssh.exec!("cat #{file}")
81
+ puts "fetch from #{url}: #{value}"
82
+ @ssh.exec!("rm #{file}")
83
+ value
84
+ end
85
+
86
+ def fetch_from_file(file)
87
+ @ssh.exec!("touch #{file}")
88
+ value = @ssh.exec!("cat #{file}")
89
+ puts "fetch from #{file}: #{value}"
90
+ value
91
+ end
92
+
93
+ def write_to_file(file, text)
94
+ puts "write to #{file}: #{text}"
95
+ cmd = "cat >#{file} <<EOS
96
+ #{text}EOS"
97
+ @ssh.exec!(cmd)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,95 @@
1
+ require 'rubygems'
2
+ require 'EC2'
3
+ require 'active_support'
4
+ require 'ec2/instance_binding'
5
+ require 'ec2/pending'
6
+ require 'base64'
7
+
8
+ module Ec2
9
+ class Manager
10
+
11
+ def initialize(cloud)
12
+ @cloud = cloud
13
+
14
+ # access_key = ENV["AMAZON_ACCESS_KEY_ID"]
15
+ # secret_key = ENV["AMAZON_SECRET_ACCESS_KEY"]
16
+ # server = "#{cloud.region}.ec2.amazonaws.com"
17
+
18
+ access_key = ENV["AMAZON_ACCESS_KEY_ID"]
19
+ secret_key = ENV["AMAZON_SECRET_ACCESS_KEY"]
20
+ server = "eu-west-1.ec2.amazonaws.com"
21
+
22
+ @ws = EC2::Base.new(:access_key_id => access_key,:secret_access_key => secret_key, :server => server)
23
+ end
24
+
25
+ def instance_bindings(&block)
26
+ bindings = {}
27
+
28
+ @ws.describe_instances.try(:reservationSet).try(:item).try(:each) do |item|
29
+ instance = item.instancesSet.item.first
30
+
31
+ id = instance.instanceId
32
+ launch_time = instance.launchTime
33
+ state = instance.instanceState.name.try(:gsub, '-', '_').try(:to_sym)
34
+ public_dns_name = instance.dnsName
35
+ private_dns_name = instance.privateDnsName
36
+
37
+ next unless state == :running
38
+
39
+ binding = InstanceBinding.new(@cloud, @ws, id, launch_time, public_dns_name, private_dns_name)
40
+
41
+ hostname = binding.hostname
42
+
43
+ next unless hostname
44
+
45
+ raise "multiple instance using hostname #{binding.hostname}" if bindings.key?(hostname)
46
+
47
+ bindings[hostname] = binding
48
+ end
49
+
50
+ bindings
51
+ end
52
+
53
+ def startup(instance)
54
+
55
+ unless Pending.pending?(instance.name)
56
+ opts = {
57
+ :image_id => instance.ami,
58
+ :min_count => 1,
59
+ :max_count => 1,
60
+ :key_name => instance.keypair,
61
+ :user_data => Base64.encode64(instance.name),
62
+ :instance_type => "m1.small"
63
+ }
64
+
65
+ opts[:availability_zone] = instance.availability_zone if instance.availability_zone
66
+
67
+ puts "startup #{instance.name}: #{opts.inspect}"
68
+
69
+ @ws.run_instances(opts)
70
+
71
+ Pending.add(instance.name)
72
+ else
73
+ puts "instance #{instance.name} is pending"
74
+ end
75
+ end
76
+
77
+ def sync(&block)
78
+
79
+ bindings = instance_bindings
80
+
81
+ bindings.each_pair do |hostname, binding|
82
+ yield(binding)
83
+ binding.disconnect!
84
+ end
85
+
86
+ @cloud.instances.each do |instance|
87
+ unless bindings.key?(instance.name)
88
+ startup(instance)
89
+ end
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,44 @@
1
+ module Ec2
2
+ class Pending
3
+
4
+ @@file = "/tmp/.ec2_pending"
5
+
6
+ def self.__load_or_create()
7
+ unless File.exist?(@@file)
8
+ __write([])
9
+ end
10
+
11
+ YAML.load(File.read(@@file))
12
+ end
13
+
14
+ def self.__write(pending)
15
+ File.open(@@file, "w") do |f|
16
+ f.write(pending.to_yaml)
17
+ end
18
+ end
19
+
20
+ def self.add(hostname)
21
+ pending = __load_or_create
22
+
23
+ unless pending.include?(hostname)
24
+ puts "add pending #{hostname}"
25
+ pending << hostname
26
+ __write(pending)
27
+ end
28
+ end
29
+
30
+ def self.remove(hostname)
31
+ pending = __load_or_create
32
+
33
+ if pending.delete(hostname)
34
+ puts "remove pending #{hostname}"
35
+ __write(pending)
36
+ end
37
+ end
38
+
39
+ def self.pending?(hostname)
40
+ __load_or_create.include?(hostname)
41
+ end
42
+
43
+ end
44
+ end
data/lib/ec2_init.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+
4
+ require 'ec2/dsl/cloud'
5
+ require 'ec2/manager'
6
+
7
+ ::EasyDsl::Container.send(:define_method, :cloud) do
8
+ @container.cloud
9
+ end
10
+
11
+ def ec2(name="default", &block)
12
+ ec2 = Ec2::Dsl::Cloud.new(name)
13
+ ec2.instance_eval(&block)
14
+ ec2.freeze_attributes
15
+ ec2.validate
16
+ ec2
17
+ end
18
+
19
+
20
+
21
+ cloud = ec2 do
22
+
23
+ ssh_key_file "/Users/jzimmek/ec2-stuff/id-jzimmek-eu-west-1"
24
+
25
+ keypair "jzimmek"
26
+ region "eu-west-1"
27
+ security_group "default"
28
+ availability_zone "eu-west-1a"
29
+
30
+ group "app" do
31
+
32
+ ami "ami-0db89079"
33
+
34
+ instance "app01" do
35
+ end
36
+
37
+ instance "app02" do
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ #
44
+ # cloud.dump
45
+ #
46
+
47
+
48
+
49
+ mgr = Ec2::Manager.new(cloud)
50
+
51
+ mgr.sync do |binding|
52
+
53
+ if binding.valid?
54
+
55
+ binding.ensure_configured('host') do |ssh|
56
+ ssh.exec!("echo \"#{binding.hostname}\" > /etc/hostname")
57
+ ssh.exec!("echo \"#{binding.public_ip} #{binding.hostname}\" >> /etc/hosts")
58
+ ssh.exec!("hostname #{binding.hostname}")
59
+ end
60
+
61
+ binding.ensure_configured('nagios-config') do |ssh|
62
+ exec("janw.php #{binding.instance.hostname} ")
63
+ end
64
+
65
+
66
+
67
+ else
68
+ binding.terminate!
69
+ end
70
+
71
+ end
data/test/ec2_test.rb ADDED
@@ -0,0 +1,83 @@
1
+ require 'test_helper'
2
+
3
+ class Ec2Test < Test::Unit::TestCase
4
+
5
+ should "create a cloud with one group and two instances" do
6
+
7
+ cloud = ec2 do
8
+ ssh_key_file "somefile"
9
+ keypair "mykeypair"
10
+ region "us-east-1"
11
+ availability_zone "zone-2"
12
+ security_group "mysecuritygroup"
13
+ group "app_server" do
14
+ ami "ami999"
15
+ instance "app01" do
16
+ security_group "default2"
17
+ availability_zone "zone-1"
18
+ end
19
+ instance "app02" do
20
+ ami "ami123"
21
+ security_group "default"
22
+ end
23
+ end
24
+ group "webserver" do
25
+ instance "web01" do
26
+ ami "webXYZ"
27
+ availability_zone "zone-3"
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ assert_equal 2, cloud.all_group.length
34
+ assert_equal "app_server", cloud.all_group["app_server"].name
35
+ assert_equal "mykeypair", cloud.keypair
36
+ assert_equal "us-east-1", cloud.region
37
+ assert_equal "zone-2", cloud.availability_zone
38
+ assert_equal "mysecuritygroup", cloud.security_group
39
+
40
+ assert_equal 3, cloud.instances.length
41
+
42
+ grp_app = cloud.all_group["app_server"]
43
+
44
+ assert_equal "app_server", grp_app.name
45
+ assert_equal 2, grp_app.all_instance.length
46
+
47
+ app01 = grp_app.all_instance["app01"]
48
+ app02 = grp_app.all_instance["app02"]
49
+
50
+ assert_equal "mykeypair", app01.keypair
51
+ assert_equal "default2", app01.security_group
52
+ assert_equal "ami999", app01.ami
53
+ assert_equal "app01", app01.name
54
+ assert_equal "zone-1", app01.availability_zone
55
+ assert_equal grp_app, app01.container
56
+ assert_equal cloud, app01.cloud
57
+
58
+ assert_equal "mykeypair", app02.keypair
59
+ assert_equal "default", app02.security_group
60
+ assert_equal "ami123", app02.ami
61
+ assert_equal "app02", app02.name
62
+ assert_equal "zone-2", app02.availability_zone
63
+ assert_equal grp_app, app02.container
64
+ assert_equal cloud, app02.cloud
65
+
66
+ grp_web = cloud.all_group["webserver"]
67
+
68
+ assert_equal "webserver", grp_web.name
69
+ assert_equal 1, grp_web.all_instance.length
70
+
71
+ web01 = grp_web.all_instance["web01"]
72
+
73
+ assert_equal "mykeypair", web01.keypair
74
+ assert_equal "mysecuritygroup", web01.security_group
75
+ assert_equal "webXYZ", web01.ami
76
+ assert_equal "web01", web01.name
77
+ assert_equal "zone-3", web01.availability_zone
78
+ assert_equal grp_web, web01.container
79
+ assert_equal cloud, web01.cloud
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+
8
+ require 'ec2_init'
9
+
10
+ class Test::Unit::TestCase
11
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jzimmek-ec2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Jan Zimmek
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-14 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: jan.zimmek@web.de
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - README
26
+ - Rakefile
27
+ - VERSION
28
+ - ec2.gemspec
29
+ - lib/ec2/dsl/cloud.rb
30
+ - lib/ec2/dsl/group.rb
31
+ - lib/ec2/dsl/instance.rb
32
+ - lib/ec2/instance_binding.rb
33
+ - lib/ec2/manager.rb
34
+ - lib/ec2/pending.rb
35
+ - lib/ec2_init.rb
36
+ - test/ec2_test.rb
37
+ - test/test_helper.rb
38
+ has_rdoc: false
39
+ homepage: http://github.com/jzimmek/ec2
40
+ post_install_message:
41
+ rdoc_options:
42
+ - --charset=UTF-8
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Management tool for EC2 clouds
64
+ test_files:
65
+ - test/ec2_test.rb
66
+ - test/test_helper.rb