stem 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/stem/group.rb ADDED
@@ -0,0 +1,104 @@
1
+ module Stem
2
+ module Group
3
+ include Util
4
+ extend self
5
+
6
+ ## Example Rules
7
+
8
+ ## icmp://1.2.3.4/32
9
+ ## icmp://GroupName
10
+ ## icmp://GroupName@UserId
11
+ ## icmp://@UserId
12
+ ## tcp://0.0.0.0/0:22
13
+ ## tcp://0.0.0.0/0:22-23
14
+ ## tcp://10.0.0.0/8: (this imples 0-65535
15
+ ## udp://GroupName:4567
16
+ ## udp://GroupName@UserID:4567-9999
17
+
18
+ def get(name)
19
+ swirl.call("DescribeSecurityGroups", "GroupName.1" => name)["securityGroupInfo"].first
20
+ rescue Swirl::InvalidRequest => e
21
+ raise e unless e.message =~ /The security group '\S+' does not exist/
22
+ nil
23
+ end
24
+
25
+ def create(name, rules = nil)
26
+ create!(name, rules)
27
+ true
28
+ rescue Swirl::InvalidRequest => e
29
+ raise e unless e.message =~ /The security group '\S+' already exists/
30
+ false
31
+ end
32
+
33
+ def create!(name, rules = nil)
34
+ description = {}
35
+ swirl.call "CreateSecurityGroup", "GroupName" => name, "GroupDescription" => "%%" + description.to_json
36
+ auth(name, rules) if rules
37
+ end
38
+
39
+ def destroy(name)
40
+ destroy!(name)
41
+ true
42
+ rescue Swirl::InvalidRequest => e
43
+ puts "===> #{e.class}"
44
+ puts "===> #{e.message}"
45
+ puts "#{e.backtrace.join("\n")}"
46
+ false
47
+ end
48
+
49
+ def destroy!(name)
50
+ swirl.call "DeleteSecurityGroup", "GroupName" => name
51
+ end
52
+
53
+ def auth(name, rules)
54
+ index = 0
55
+ args = rules.inject({"GroupName" => name}) do |i,rule|
56
+ index += 1;
57
+ rule_hash = gen_authorize(index, rule)
58
+ i.merge(rule_hash)
59
+ end
60
+ swirl.call "AuthorizeSecurityGroupIngress", args
61
+ end
62
+
63
+ def gen_authorize_target(index, target)
64
+ if target =~ /^\d+\.\d+\.\d+.\d+\/\d+$/
65
+ { "IpPermissions.#{index}.IpRanges.1.CidrIp" => target }
66
+ elsif target =~ /^(\w+)@(\w+)$/
67
+ { "IpPermissions.#{index}.Groups.1.GroupName" => $1,
68
+ "IpPermissions.#{index}.Groups.1.UserId" => $2 }
69
+ elsif target =~ /^@(\w+)$/
70
+ { "IpPermissions.#{index}.Groups.1.UserId" => $1 }
71
+ else
72
+ { "IpPermissions.#{index}.Groups.1.GroupName" => target }
73
+ end
74
+ end
75
+
76
+ def gen_authorize_ports(index, ports)
77
+ if ports =~ /^(\d+)-(\d+)$/
78
+ { "IpPermissions.#{index}.FromPort" => $1,
79
+ "IpPermissions.#{index}.ToPort" => $2 }
80
+ elsif ports =~ /^(\d+)$/
81
+ { "IpPermissions.#{index}.FromPort" => $1,
82
+ "IpPermissions.#{index}.ToPort" => $1 }
83
+ elsif ports == ""
84
+ { "IpPermissions.#{index}.FromPort" => "0",
85
+ "IpPermissions.#{index}.ToPort" => "65535" }
86
+ else
87
+ raise "bad ports: #{rule}"
88
+ end
89
+ end
90
+
91
+ def gen_authorize(index, rule)
92
+ if rule =~ /icmp:\/\/(.+)/
93
+ { "IpPermissions.#{index}.IpProtocol" => "icmp",
94
+ "IpPermissions.#{index}.FromPort" => "-1",
95
+ "IpPermissions.#{index}.ToPort" => "-1" }.merge(gen_authorize_target(index,$1))
96
+ elsif rule =~ /(tcp|udp):\/\/(.*):(.*)/
97
+ { "IpPermissions.#{index}.IpProtocol" => $1 }.merge(gen_authorize_target(index,$2)).merge(gen_authorize_ports(index,$3))
98
+ else
99
+ raise "bad rule: #{rule}"
100
+ end
101
+ end
102
+ end
103
+ end
104
+
data/lib/stem/instance.rb CHANGED
@@ -16,15 +16,15 @@ module Stem
16
16
  throw "No AMI specified." unless ami
17
17
 
18
18
  opt = {
19
- "MinCount" => "1",
20
- "MaxCount" => "1",
21
- "KeyName" => config["key_name"] || "default",
22
- "InstanceType" => config["instance_type"] || "m1.small",
23
- "ImageId" => ami
19
+ "SecurityGroup.#" => config["groups"] || [],
20
+ "MinCount" => "1",
21
+ "MaxCount" => "1",
22
+ "KeyName" => config["key_name"] || "default",
23
+ "InstanceType" => config["instance_type"] || "m1.small",
24
+ "ImageId" => ami
24
25
  }
25
- if config["availability_zone"]
26
- opt.merge! "Placement.AvailabilityZone" => config["availability_zone"]
27
- end
26
+
27
+ opt.merge! "Placement.AvailabilityZone" => config["availability_zone"] if config["availability_zone"]
28
28
 
29
29
  if config["volumes"]
30
30
  devices = []
@@ -46,11 +46,11 @@ module Stem
46
46
 
47
47
  response = swirl.call "RunInstances", opt
48
48
 
49
- puts "Success!"
50
49
  response["instancesSet"].each do |i|
51
50
  return i["instanceId"]
52
51
  end
53
52
  end
53
+
54
54
  def restart instance_id
55
55
  swirl.call "RebootInstances", "InstanceId" => instance_id
56
56
  end
@@ -93,18 +93,20 @@ module Stem
93
93
  puts "Instances"
94
94
  puts "------------------------------------------"
95
95
  instances["reservationSet"].each do |r|
96
+ groups = r["groupSet"].map { |g| g["groupId"] }.join(",")
96
97
  r["instancesSet"].each do |i|
97
98
  name = lookup[i["imageId"]]
98
- puts "%-15s %-15s %-15s %s" % [ i["instanceId"], i["ipAddress"] || "no ip", i["instanceState"]["name"], name ]
99
+ puts "%-15s %-15s %-15s %-20s %s" % [ i["instanceId"], i["ipAddress"] || "no ip", i["instanceState"]["name"], groups, name ]
99
100
  end
100
101
  end
101
102
 
102
103
  puts "------------------------------------------"
103
104
  puts "AMIs"
104
105
  puts "------------------------------------------"
105
- images = c.call "DescribeImages", "Owner" => "self"
106
- images["imagesSet"].each do
107
- puts "%-15s %s" % [ img["name"], img["imageId"] ]
106
+ images = swirl.call "DescribeImages", "Owner" => "self"
107
+ iwidth = images["imagesSet"].map { |img| img["name"].length }.max + 1
108
+ images["imagesSet"].each do |img|
109
+ puts "%-#{iwidth}s %s" % [ img["name"], img["imageId"] ]
108
110
  end
109
111
  end
110
112
  end
@@ -0,0 +1,69 @@
1
+ require 'tmpdir'
2
+ require 'fileutils'
3
+
4
+ module Stem
5
+ module Userdata
6
+ CREATE_ONLY = File::CREAT|File::EXCL|File::WRONLY
7
+
8
+ extend self
9
+
10
+ def compile(path, opts = {})
11
+ raise "No absolute paths please" if path.index("/") == 0
12
+ raise "must be a directory" unless File.directory?(path)
13
+ Dir.mktmpdir do |tmp_path|
14
+ # trailing dot copies directory contents to match actual cp -r semantics... go figure
15
+ FileUtils.cp_r("#{path}/.", tmp_path)
16
+ Dir.chdir tmp_path do
17
+ process_erb(opts[:erb_binding])
18
+ process_mustache(opts[:mustache_vars])
19
+ raise "must contain a userdata.sh" unless File.exists?("userdata.sh")
20
+ make_zip_shell
21
+ end
22
+ end
23
+ end
24
+
25
+ # todo: make this & process_mustache both use binding
26
+ def process_erb(binding)
27
+ Dir["**/*.erb.stem"].each do |file|
28
+ raise "must pass :erb_binding when using .erb.stem files" unless binding
29
+ require 'erb'
30
+ puts "erb ... #{file}"
31
+ File.open(file.gsub(/.erb.stem$/,""), CREATE_ONLY) do |fff|
32
+ fff.write ERB.new(File.read(file), 0, '<>').result(binding)
33
+ end
34
+ end
35
+ end
36
+
37
+ def process_mustache(vars)
38
+ Dir["**/*.mustache.stem"].each do |file|
39
+ raise "must pass :mustache_vars when using .mustache.stem files" unless vars
40
+ require 'mustache'
41
+ puts "mustache ... #{file}"
42
+ File.open(file.gsub(/.mustache.stem$/,""), CREATE_ONLY) do |fff|
43
+ fff.write Mustache.render(File.read(file), vars)
44
+ end
45
+ end
46
+ end
47
+
48
+ def make_zip_shell
49
+ # We'll comment outside here, to keep from wasting valuable userdata bytes.
50
+ # we decompress into /root/userdata, then run userdata.sh
51
+ header = <<-'SHELL'
52
+ #!/bin/bash
53
+ exec >> /var/log/userdata.log 2>&1
54
+ echo BOOTING `date`
55
+ UD=~/userdata
56
+ mkdir -p $UD
57
+ tail -n +HEADER_LINES "$0" | tar -jx -C $UD -f -
58
+ cd $UD
59
+ exec bash userdata.sh
60
+ SHELL
61
+ process_header(header) + %x{tar --exclude *.stem -cv - . | bzip2 --best -}
62
+ end
63
+
64
+ def process_header(shell)
65
+ shell.gsub(/HEADER_LINES/, (shell.split("\n").size + 1).to_s).gsub(/^ +/,'')
66
+ end
67
+ end
68
+ end
69
+
data/lib/stem.rb CHANGED
@@ -5,6 +5,8 @@ require 'json'
5
5
 
6
6
  require 'stem/cli'
7
7
  require 'stem/util'
8
+ require 'stem/group'
9
+ require 'stem/userdata'
8
10
  require 'stem/instance'
9
11
  require 'stem/image'
10
12
  require 'stem/ip'
metadata CHANGED
@@ -1,21 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stem
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Peter van Hardenberg
14
+ - Orion Henry
14
15
  autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-08-12 00:00:00 -07:00
19
+ date: 2010-10-08 00:00:00 -07:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
@@ -37,6 +38,7 @@ dependencies:
37
38
  description: minimalist EC2 instance management
38
39
  email:
39
40
  - pvh@heroku.com
41
+ - orion@heroku.com
40
42
  executables:
41
43
  - stem
42
44
  extensions: []
@@ -47,9 +49,11 @@ files:
47
49
  - LICENSE
48
50
  - README.md
49
51
  - lib/stem/cli.rb
52
+ - lib/stem/group.rb
50
53
  - lib/stem/image.rb
51
54
  - lib/stem/instance.rb
52
55
  - lib/stem/ip.rb
56
+ - lib/stem/userdata.rb
53
57
  - lib/stem/util.rb
54
58
  - lib/stem.rb
55
59
  - bin/stem