chef-workflow 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ require 'chef-workflow/support/db'
2
+
3
+ module ChefWorkflow
4
+ class DatabaseSupport
5
+ class VMGroup
6
+ include Enumerable
7
+
8
+ def initialize(table_name, box_nil)
9
+ raise "Must provide a table name!" unless table_name
10
+ @table_name = table_name
11
+ @box_nil = box_nil
12
+ @db = ChefWorkflow::DatabaseSupport.instance
13
+ create_table
14
+ end
15
+
16
+ def [](key)
17
+ rows = @db.execute("select value from #{@table_name} where name=? order by id", [key])
18
+ if rows.count == 0
19
+ @box_nil ? [] : nil
20
+ else
21
+ rows.to_a.map { |x| Marshal.load(x.first) }
22
+ end
23
+ end
24
+
25
+ def []=(key, value)
26
+ delete(key)
27
+
28
+ return value if value.empty?
29
+
30
+ values = value.map { |x| Marshal.dump(x) }
31
+ value_string = ("(?, ?)," * values.count).chop
32
+
33
+ @db.execute("insert into #{@table_name} (name, value) values #{value_string}", values.map { |x| [key, x] }.flatten)
34
+ end
35
+
36
+ def keys
37
+ @db.execute("select distinct name from #{@table_name}").map(&:first)
38
+ end
39
+
40
+ def delete(key)
41
+ @db.execute("delete from #{@table_name} where name=?", [key])
42
+ end
43
+
44
+ def has_key?(key)
45
+ @db.execute("select count(*) from #{@table_name} where name=?", [key]).first.first.to_i > 0
46
+ end
47
+
48
+ def each
49
+ # XXX very slow, but fuck it
50
+ keys.each do |key|
51
+ yield key, self[key]
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def create_table
58
+ @db.execute <<-EOF
59
+ create table if not exists #{@table_name} (
60
+ id integer not null primary key autoincrement,
61
+ name varchar(255) not null,
62
+ value text not null
63
+ )
64
+ EOF
65
+
66
+ @db.execute <<-EOF
67
+ create index if not exists #{@table_name}_name_index on #{@table_name} (name)
68
+ EOF
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,51 +1,53 @@
1
- #
2
- # mixin to assist with adding debug messages.
3
- #
4
- module DebugSupport
5
-
6
- CHEF_WORKFLOW_DEBUG_DEFAULT = 2
7
-
8
- #
9
- # Conditionally executes based on the level of debugging requested.
10
- #
11
- # `CHEF_WORKFLOW_DEBUG` in the environment is converted to an integer. This
12
- # integer is compared to the first argument. If it is higher than the first
13
- # argument, the block supplied will execute.
14
- #
15
- # Optionally, if there is a `else_block`, this block will be executed if the
16
- # condition is *not* met. This allows a slightly more elegant (if less ugly)
17
- # variant of dealing with the situation where if debugging is on, do one
18
- # thing, and if not, do something else.
19
- #
20
- # Examples:
1
+ module ChefWorkflow
21
2
  #
22
- # if_debug(1) do
23
- # $stderr.puts "Here's a debug message"
24
- # end
3
+ # mixin to assist with adding debug messages.
25
4
  #
26
- # This will print "here's a debug message" to standard error if debugging is
27
- # set to 1 or greater.
28
- #
29
- # do_thing = lambda { run_thing }
30
- # if_debug(2, &do_thing) do
31
- # $stderr.puts "Doing this thing"
32
- # do_thing.call
33
- # end
34
- #
35
- # If debugging is set to 2 or higher, "Doing this thing" will be printed to
36
- # standard error and then `run_thing` will be executed. If lower than 2 or
37
- # off, will just execute `run_thing`.
38
- #
39
- def if_debug(minimum=1, else_block=nil)
40
- $CHEF_WORKFLOW_DEBUG ||=
41
- ENV.has_key?("CHEF_WORKFLOW_DEBUG") ?
42
- ENV["CHEF_WORKFLOW_DEBUG"].to_i :
43
- CHEF_WORKFLOW_DEBUG_DEFAULT
5
+ module DebugSupport
6
+
7
+ CHEF_WORKFLOW_DEBUG_DEFAULT = 2
8
+
9
+ #
10
+ # Conditionally executes based on the level of debugging requested.
11
+ #
12
+ # `CHEF_WORKFLOW_DEBUG` in the environment is converted to an integer. This
13
+ # integer is compared to the first argument. If it is higher than the first
14
+ # argument, the block supplied will execute.
15
+ #
16
+ # Optionally, if there is a `else_block`, this block will be executed if the
17
+ # condition is *not* met. This allows a slightly more elegant (if less ugly)
18
+ # variant of dealing with the situation where if debugging is on, do one
19
+ # thing, and if not, do something else.
20
+ #
21
+ # Examples:
22
+ #
23
+ # if_debug(1) do
24
+ # $stderr.puts "Here's a debug message"
25
+ # end
26
+ #
27
+ # This will print "here's a debug message" to standard error if debugging is
28
+ # set to 1 or greater.
29
+ #
30
+ # do_thing = lambda { run_thing }
31
+ # if_debug(2, &do_thing) do
32
+ # $stderr.puts "Doing this thing"
33
+ # do_thing.call
34
+ # end
35
+ #
36
+ # If debugging is set to 2 or higher, "Doing this thing" will be printed to
37
+ # standard error and then `run_thing` will be executed. If lower than 2 or
38
+ # off, will just execute `run_thing`.
39
+ #
40
+ def if_debug(minimum=1, else_block=nil)
41
+ $CHEF_WORKFLOW_DEBUG ||=
42
+ ENV.has_key?("CHEF_WORKFLOW_DEBUG") ?
43
+ ENV["CHEF_WORKFLOW_DEBUG"].to_i :
44
+ CHEF_WORKFLOW_DEBUG_DEFAULT
44
45
 
45
- if $CHEF_WORKFLOW_DEBUG >= minimum
46
- yield if block_given?
47
- elsif else_block
48
- else_block.call
46
+ if $CHEF_WORKFLOW_DEBUG >= minimum
47
+ yield if block_given?
48
+ elsif else_block
49
+ else_block.call
50
+ end
49
51
  end
50
52
  end
51
53
  end
@@ -4,167 +4,169 @@ require 'chef-workflow/support/general'
4
4
  require 'chef-workflow/support/debug'
5
5
  require 'chef-workflow/support/attr'
6
6
 
7
- class EC2Support
8
- extend AttrSupport
9
- include DebugSupport
10
-
11
- fancy_attr :access_key_id
12
- fancy_attr :secret_access_key
13
- fancy_attr :ami
14
- fancy_attr :instance_type
15
- fancy_attr :region
16
- fancy_attr :ssh_key
17
- fancy_attr :security_groups
18
- fancy_attr :security_group_open_ports
19
- fancy_attr :provision_wait
20
-
21
- def initialize
22
- self.security_groups :auto
23
- self.security_group_open_ports [22, 4000]
24
- self.provision_wait 300
25
- end
7
+ module ChefWorkflow
8
+ class EC2Support
9
+ extend ChefWorkflow::AttrSupport
10
+ include ChefWorkflow::DebugSupport
11
+
12
+ fancy_attr :access_key_id
13
+ fancy_attr :secret_access_key
14
+ fancy_attr :ami
15
+ fancy_attr :instance_type
16
+ fancy_attr :region
17
+ fancy_attr :ssh_key
18
+ fancy_attr :security_groups
19
+ fancy_attr :security_group_open_ports
20
+ fancy_attr :provision_wait
21
+
22
+ def initialize
23
+ self.security_groups :auto
24
+ self.security_group_open_ports [22, 4000]
25
+ self.provision_wait 300
26
+ end
26
27
 
27
- def ec2_obj
28
- args =
29
- if access_key_id and secret_access_key
30
- {
31
- :access_key_id => access_key_id,
32
- :secret_access_key => secret_access_key
33
- }
34
- else
35
- {
36
- :access_key_id => ENV["AWS_ACCESS_KEY_ID"],
37
- :secret_access_key => ENV["AWS_SECRET_ACCESS_KEY"]
38
- }
39
- end
28
+ def ec2_obj
29
+ args =
30
+ if access_key_id and secret_access_key
31
+ {
32
+ :access_key_id => access_key_id,
33
+ :secret_access_key => secret_access_key
34
+ }
35
+ else
36
+ {
37
+ :access_key_id => ENV["AWS_ACCESS_KEY_ID"],
38
+ :secret_access_key => ENV["AWS_SECRET_ACCESS_KEY"]
39
+ }
40
+ end
40
41
 
41
- ec2 = AWS::EC2.new(args)
42
- ec2.regions[region]
43
- end
42
+ ec2 = AWS::EC2.new(args)
43
+ ec2.regions[region]
44
+ end
44
45
 
45
- #
46
- # Only used if security_groups is set to auto. Returns the filename to
47
- # marshal the automatically created security groups to.
48
- #
49
- def security_group_setting_path
50
- File.join(GeneralSupport.singleton.workflow_dir, 'security-groups')
51
- end
46
+ #
47
+ # Only used if security_groups is set to auto. Returns the filename to
48
+ # marshal the automatically created security groups to.
49
+ #
50
+ def security_group_setting_path
51
+ File.join(ChefWorkflow::GeneralSupport.workflow_dir, 'security-groups')
52
+ end
53
+
54
+ #
55
+ # Creates a security group and saves it to the security_group_setting_path.
56
+ #
57
+ def create_security_group
58
+ aws_ec2 = ec2_obj
52
59
 
53
- #
54
- # Creates a security group and saves it to the security_group_setting_path.
55
- #
56
- def create_security_group
57
- aws_ec2 = ec2_obj
60
+ name = nil
58
61
 
59
- name = nil
62
+ loop do
63
+ name = 'chef-workflow-' + (0..rand(10).to_i).map { rand(0..9).to_s }.join("")
60
64
 
61
- loop do
62
- name = 'chef-workflow-' + (0..rand(10).to_i).map { rand(0..9).to_s }.join("")
65
+ if_debug(3) do
66
+ $stderr.puts "Seeing if security group name #{name} is taken"
67
+ end
63
68
 
64
- if_debug(3) do
65
- $stderr.puts "Seeing if security group name #{name} is taken"
69
+ break unless aws_ec2.security_groups[name].exists?
70
+ sleep 0.3
66
71
  end
67
72
 
68
- break unless aws_ec2.security_groups[name].exists?
69
- sleep 0.3
70
- end
73
+ group = aws_ec2.security_groups.create(name)
71
74
 
72
- group = aws_ec2.security_groups.create(name)
75
+ security_group_open_ports.each do |port|
76
+ group.authorize_ingress(:tcp, port)
77
+ group.authorize_ingress(:udp, port)
78
+ end
79
+
80
+ group.authorize_ingress(:tcp, (0..65535), group)
81
+ group.authorize_ingress(:udp, (0..65535), group)
73
82
 
74
- security_group_open_ports.each do |port|
75
- group.authorize_ingress(:tcp, port)
76
- group.authorize_ingress(:udp, port)
83
+ # XXX I think the name should be enough, but maybe this'll cause a problem.
84
+ File.binwrite(security_group_setting_path, Marshal.dump([name]))
85
+ return [name]
77
86
  end
78
87
 
79
- group.authorize_ingress(:tcp, (0..65535), group)
80
- group.authorize_ingress(:udp, (0..65535), group)
88
+ #
89
+ # Loads any stored security groups. Returns nil if it can't.
90
+ #
91
+ def load_security_group
92
+ Marshal.load(File.binread(security_group_setting_path)) rescue nil
93
+ end
81
94
 
82
- # XXX I think the name should be enough, but maybe this'll cause a problem.
83
- File.binwrite(security_group_setting_path, Marshal.dump([name]))
84
- return [name]
85
- end
95
+ #
96
+ # Ensures security groups exist.
97
+ #
98
+ # If @security_groups is :auto, creates one and sets it up with the
99
+ # security_group_open_ports on TCP and UDP.
100
+ #
101
+ # If @security_groups is an array of group names or a single group name,
102
+ # asserts they exist. If they do not exist, it raises.
103
+ #
104
+ def assert_security_groups
105
+ aws_ec2 = ec2_obj
106
+
107
+ if security_groups == :auto
108
+ loaded_groups = load_security_group
109
+
110
+ # this will make it hit the second block everytime from now on (and
111
+ # bootstrap it recursively)
112
+ if loaded_groups
113
+ self.security_groups loaded_groups
114
+ assert_security_groups
115
+ else
116
+ self.security_groups create_security_group
117
+ end
118
+ else
119
+ self.security_groups = [security_groups] unless security_groups.kind_of?(Array)
86
120
 
87
- #
88
- # Loads any stored security groups. Returns nil if it can't.
89
- #
90
- def load_security_group
91
- Marshal.load(File.binread(security_group_setting_path)) rescue nil
92
- end
121
+ self.security_groups.each do |group|
122
+ #
123
+ # just retry this until it works -- some stupid flexible proxy in aws-sdk will bark about a missing method otherwise.
124
+ #
93
125
 
94
- #
95
- # Ensures security groups exist.
96
- #
97
- # If @security_groups is :auto, creates one and sets it up with the
98
- # security_group_open_ports on TCP and UDP.
99
- #
100
- # If @security_groups is an array of group names or a single group name,
101
- # asserts they exist. If they do not exist, it raises.
102
- #
103
- def assert_security_groups
104
- aws_ec2 = ec2_obj
105
-
106
- if security_groups == :auto
107
- loaded_groups = load_security_group
108
-
109
- # this will make it hit the second block everytime from now on (and
110
- # bootstrap it recursively)
111
- if loaded_groups
112
- self.security_groups loaded_groups
113
- assert_security_groups
114
- else
115
- self.security_groups create_security_group
116
- end
117
- else
118
- self.security_groups = [security_groups] unless security_groups.kind_of?(Array)
119
-
120
- self.security_groups.each do |group|
121
- #
122
- # just retry this until it works -- some stupid flexible proxy in aws-sdk will bark about a missing method otherwise.
123
- #
124
-
125
- begin
126
- aws_ec2.security_groups[group]
127
- rescue
128
- sleep 1
129
- retry
130
- end
126
+ begin
127
+ aws_ec2.security_groups[group]
128
+ rescue
129
+ sleep 1
130
+ retry
131
+ end
131
132
 
132
- raise "EC2 security group #{group} does not exist and it should." unless aws_ec2.security_groups[group]
133
+ raise "EC2 security group #{group} does not exist and it should." unless aws_ec2.security_groups[group]
134
+ end
133
135
  end
134
136
  end
135
- end
136
137
 
137
- def find_secgroup_running_instances(group_name)
138
- # exponential complexity with API calls? NO PROBLEM
139
- ec2_obj.instances.select do |i|
140
- i.status != :terminated &&
141
- i.security_groups.find { |s| s.name == group_name }
138
+ def find_secgroup_running_instances(group_name)
139
+ # exponential complexity with API calls? NO PROBLEM
140
+ ec2_obj.instances.select do |i|
141
+ i.status != :terminated &&
142
+ i.security_groups.find { |s| s.name == group_name }
143
+ end
142
144
  end
143
- end
144
145
 
145
- def destroy_security_group
146
- if File.exist?(security_group_setting_path)
147
- group_name = Marshal.load(File.binread(security_group_setting_path)).first
146
+ def destroy_security_group
147
+ if File.exist?(security_group_setting_path)
148
+ group_name = Marshal.load(File.binread(security_group_setting_path)).first
148
149
 
149
- until (instances = find_secgroup_running_instances(group_name)).empty?
150
- if_debug(1) do
151
- $stderr.puts "Trying to destroy security group #{group_name}, but instances are still bound to it."
152
- $stderr.puts instances.map(&:id).inspect
153
- $stderr.puts "Terminating instances, sleeping, and trying again."
154
- end
155
-
156
- instances.each do |i|
157
- i.terminate rescue nil
150
+ until (instances = find_secgroup_running_instances(group_name)).empty?
151
+ if_debug(1) do
152
+ $stderr.puts "Trying to destroy security group #{group_name}, but instances are still bound to it."
153
+ $stderr.puts instances.map(&:id).inspect
154
+ $stderr.puts "Terminating instances, sleeping, and trying again."
155
+ end
156
+
157
+ instances.each do |i|
158
+ i.terminate rescue nil
159
+ end
160
+
161
+ sleep 10
158
162
  end
159
163
 
160
- sleep 10
164
+ ec2_obj.security_groups.find { |g| g.name == group_name }.delete
161
165
  end
162
-
163
- ec2_obj.security_groups.find { |g| g.name == group_name }.delete
164
166
  end
165
- end
166
167
 
167
- include GenericSupport
168
+ include ChefWorkflow::GenericSupport
169
+ end
168
170
  end
169
171
 
170
- EC2Support.configure
172
+ ChefWorkflow::EC2Support.configure