chef-vpc-toolkit 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +2 -0
  2. data/COPYING +26 -0
  3. data/README.rdoc +75 -0
  4. data/Rakefile +34 -0
  5. data/VERSION +1 -0
  6. data/bin/chef-vpc-toolkit +80 -0
  7. data/config/chef_installer.yml +20 -0
  8. data/config/databags.json.example +24 -0
  9. data/config/nodes.json +10 -0
  10. data/config/server_group.json +16 -0
  11. data/contrib/doc/ChefVPCToolkit.odt +0 -0
  12. data/contrib/doc/ChefVPCToolkit.pdf +0 -0
  13. data/contrib/etc/chef_vpc_toolkit.conf +10 -0
  14. data/contrib/rake/Rakefile +23 -0
  15. data/cookbook-repos/local/README +5 -0
  16. data/cookbook-repos/local/Rakefile +66 -0
  17. data/cookbook-repos/local/certificates/README +1 -0
  18. data/cookbook-repos/local/config/client.rb.example +21 -0
  19. data/cookbook-repos/local/config/knife.rb.example +10 -0
  20. data/cookbook-repos/local/config/rake.rb +60 -0
  21. data/cookbook-repos/local/config/server.rb.example +42 -0
  22. data/cookbook-repos/local/config/solo.rb.example +13 -0
  23. data/cookbook-repos/local/cookbooks/README +4 -0
  24. data/cookbook-repos/local/cookbooks/motd/README.rdoc +15 -0
  25. data/cookbook-repos/local/cookbooks/motd/attributes/motd.rb +1 -0
  26. data/cookbook-repos/local/cookbooks/motd/metadata.rb +6 -0
  27. data/cookbook-repos/local/cookbooks/motd/recipes/default.rb +13 -0
  28. data/cookbook-repos/local/cookbooks/motd/templates/default/motd.erb +1 -0
  29. data/cookbook-repos/local/roles/README +4 -0
  30. data/lib/chef-vpc-toolkit.rb +6 -0
  31. data/lib/chef-vpc-toolkit/chef-0.9.bash +232 -0
  32. data/lib/chef-vpc-toolkit/chef_bootstrap/centos.bash +47 -0
  33. data/lib/chef-vpc-toolkit/chef_bootstrap/fedora.bash +41 -0
  34. data/lib/chef-vpc-toolkit/chef_bootstrap/rhel.bash +38 -0
  35. data/lib/chef-vpc-toolkit/chef_bootstrap/ubuntu.bash +32 -0
  36. data/lib/chef-vpc-toolkit/chef_installer.rb +276 -0
  37. data/lib/chef-vpc-toolkit/cloud_files.bash +67 -0
  38. data/lib/chef-vpc-toolkit/cloud_servers_vpc.rb +285 -0
  39. data/lib/chef-vpc-toolkit/http_util.rb +117 -0
  40. data/lib/chef-vpc-toolkit/ssh_util.rb +22 -0
  41. data/lib/chef-vpc-toolkit/util.rb +56 -0
  42. data/lib/chef-vpc-toolkit/version.rb +8 -0
  43. data/rake/chef_vpc_toolkit.rake +284 -0
  44. data/test/cloud_servers_vpc_test.rb +174 -0
  45. data/test/test_helper.rb +25 -0
  46. metadata +153 -0
@@ -0,0 +1,8 @@
1
+ module ChefVPCToolkit
2
+
3
+ class Version
4
+ CHEF_VPC_TOOLKIT_ROOT = File.dirname(File.expand_path("../", File.dirname(__FILE__)))
5
+ VERSION = IO.read(File.join(CHEF_VPC_TOOLKIT_ROOT, 'VERSION'))
6
+ end
7
+
8
+ end
@@ -0,0 +1,284 @@
1
+ #require 'chef-cloud-toolkit'
2
+
3
+ namespace :group do
4
+ TMP_SG=File.join(CHEF_VPC_PROJECT, 'tmp', 'server_groups')
5
+
6
+ directory TMP_SG
7
+
8
+ desc "Create a new group of cloud servers"
9
+ task :create => [ TMP_SG, "chef:validate_json" ] do
10
+
11
+ request=CloudServersVPC.server_group_xml
12
+ configs=Util.load_configs
13
+
14
+ resp=HttpUtil.post(
15
+ configs["cloud_servers_vpc_url"]+"/server_groups.xml",
16
+ request,
17
+ configs["cloud_servers_vpc_username"],
18
+ configs["cloud_servers_vpc_password"]
19
+ )
20
+
21
+ hash=CloudServersVPC.server_group_hash(resp)
22
+ out_file=hash["id"]+".xml"
23
+ File.open(File.join(TMP_SG, out_file), 'w') { |f| f.write(resp) }
24
+ puts "Cloud server group ID #{hash['id']} created."
25
+
26
+ end
27
+
28
+ desc "List existing cloud server groups"
29
+ task :list => TMP_SG do
30
+
31
+ server_groups=[]
32
+ Dir[File.join(TMP_SG, '*.xml')].each do |file|
33
+ server_groups << CloudServersVPC.server_group_hash(IO.read(file))
34
+ end
35
+ if server_groups.size > 0
36
+ puts "Cloud server groups:"
37
+ server_groups.sort { |a,b| b["id"] <=> a["id"] }.each do |sg|
38
+ gw=sg['vpn-gateway'].nil? ? "" : " (#{sg['vpn-gateway']})"
39
+ puts "\t#{sg['id']}: #{sg['name']}#{gw}"
40
+ end
41
+ else
42
+ puts "No server groups."
43
+ end
44
+
45
+ end
46
+
47
+ desc "Print information for a cloud server group"
48
+ task :show => TMP_SG do
49
+ id=ENV['GROUP_ID']
50
+ configs=Util.load_configs
51
+ xml=CloudServersVPC.server_group_xml_for_id(configs, File.join(TMP_SG, '*.xml'), id)
52
+
53
+ hash=CloudServersVPC.server_group_hash(xml)
54
+ File.open(File.join(TMP_SG, "#{hash['id']}.xml"), 'w') { |f| f.write(xml) }
55
+ CloudServersVPC.print_server_group(hash)
56
+
57
+ end
58
+
59
+ desc "Delete a cloud server group"
60
+ task :delete do
61
+ id=ENV['GROUP_ID']
62
+ configs=Util.load_configs
63
+ hash=Util.hash_for_group
64
+ if id.nil? then
65
+ id=hash["id"]
66
+ end
67
+ SshUtil.remove_known_hosts_ip(hash["vpn-gateway"])
68
+ puts "Deleting cloud server group ID: #{id}."
69
+ HttpUtil.delete(
70
+ configs["cloud_servers_vpc_url"]+"/server_groups/#{id}.xml",
71
+ configs["cloud_servers_vpc_username"],
72
+ configs["cloud_servers_vpc_password"]
73
+ )
74
+ File.delete(File.join(TMP_SG, "#{id}.xml"))
75
+ end
76
+
77
+ desc "Force clean the cached server group files"
78
+ task :force_clean do
79
+ puts "Removing cached server group files."
80
+ FileUtils.rm_rf(TMP_SG)
81
+ end
82
+
83
+ desc "Poll/loop until a server group is online"
84
+ task :poll do
85
+ timeout=ENV['TIMEOUT']
86
+ if timeout.nil? or timeout.empty? then
87
+ timeout=1500 # defaults to 24 minutes
88
+ end
89
+ hash=Util.hash_for_group
90
+ puts "Polling for server(s) to come online (this may take a couple minutes)..."
91
+ servers=nil
92
+ vpn_gateway=nil
93
+ CloudServersVPC.poll_until_online(hash["id"], timeout) do |server_group_hash|
94
+ if servers != server_group_hash then
95
+ servers = server_group_hash
96
+ vpn_gateway = server_group_hash["vpn-gateway"] if server_group_hash["vpn-gateway"]
97
+ if not vpn_gateway.nil? and not vpn_gateway.empty? then
98
+ SshUtil.remove_known_hosts_ip(vpn_gateway)
99
+ end
100
+ ENV["GROUP_ID"]=server_group_hash['id']
101
+ CloudServersVPC.print_server_group(server_group_hash)
102
+ end
103
+ end
104
+ Rake::Task['group:show'].invoke
105
+ puts "Cloud server group online."
106
+ end
107
+
108
+ end
109
+
110
+ namespace :server do
111
+
112
+ desc "Rebuild a server in a server group."
113
+ task :rebuild => TMP_SG do
114
+ id=ENV['GROUP_ID']
115
+ server_name=ENV['SERVER_NAME']
116
+ raise "Please specify a SERVER_NAME." if server_name.nil?
117
+ configs=Util.load_configs
118
+
119
+ xml=CloudServersVPC.server_group_xml_for_id(configs, File.join(TMP_SG, '*.xml'), id)
120
+ hash=CloudServersVPC.server_group_hash(xml)
121
+ CloudServersVPC.rebuild(hash, server_name)
122
+
123
+ end
124
+
125
+ end
126
+
127
+ namespace :chef do
128
+
129
+ desc "Validate the Chef JSON config file."
130
+ task :validate_json do
131
+
132
+ configs=ChefInstaller.load_configs
133
+ ChefInstaller.validate_json(configs)
134
+
135
+ end
136
+
137
+ desc "Install and configure Chef on the server group"
138
+ task :install do
139
+
140
+ configs=ChefInstaller.load_configs
141
+ configs.merge!(Util.load_configs)
142
+ hash=Util.hash_for_group(configs)
143
+ os_types=CloudServersVPC.os_types(hash)
144
+ configs["ssh_gateway_ip"]=hash["vpn-gateway"]
145
+ client_validation_key=ChefInstaller.install_chef_server(configs, os_types)
146
+ ChefInstaller.create_databags(configs)
147
+ ChefInstaller.install_chef_clients(configs, client_validation_key, os_types)
148
+
149
+ end
150
+
151
+ desc "Tail the Chef client logs"
152
+ task :tail_logs do
153
+
154
+ lines=ENV['LINES']
155
+ if lines.nil? or lines.empty? then
156
+ lines=100
157
+ end
158
+ configs=ChefInstaller.load_configs
159
+ hash=Util.hash_for_group(configs)
160
+ CloudServersVPC.server_names(hash) do |name|
161
+ puts "================================================================================"
162
+ puts "SERVER NAME: #{name}"
163
+ puts ChefInstaller.tail_log(hash["vpn-gateway"], name, "/var/log/chef/client.log", lines)
164
+ end
165
+
166
+ end
167
+
168
+ desc "Sync the local cookbook repos directory to the Chef server."
169
+ task :sync_repos do
170
+
171
+ configs=ChefInstaller.load_configs
172
+ hash=Util.hash_for_group(configs)
173
+ configs["ssh_gateway_ip"]=hash["vpn-gateway"]
174
+ ChefInstaller.rsync_cookbook_repos(configs)
175
+
176
+ end
177
+
178
+ desc "Create/Update databags on the Chef server."
179
+ task :databags do
180
+
181
+ configs=ChefInstaller.load_configs
182
+ hash=Util.hash_for_group(configs)
183
+ configs["ssh_gateway_ip"]=hash["vpn-gateway"]
184
+ ChefInstaller.create_databags(configs)
185
+
186
+ end
187
+
188
+ end
189
+
190
+ namespace :share do
191
+
192
+ desc "Sync the share data."
193
+ task :sync do
194
+
195
+ if File.exists?("#{CHEF_VPC_PROJECT}/share/") then
196
+ puts "Syncing share data."
197
+ configs=Util.load_configs
198
+ hash=Util.hash_for_group(configs)
199
+ system("rsync -azL '#{CHEF_VPC_PROJECT}/share/' root@#{hash['vpn-gateway']}:/mnt/share/")
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+
206
+ desc "SSH into the most recently created VPN gateway server."
207
+ task :ssh do
208
+ hash=Util.hash_for_group
209
+ exec("ssh root@#{hash['vpn-gateway']}")
210
+ end
211
+
212
+ desc "Create a server group, install chef, sync share data and cookbooks."
213
+ task :create do
214
+
215
+ Rake::Task['group:create'].invoke
216
+ Rake::Task['group:poll'].invoke
217
+ Rake::Task['chef:sync_repos'].invoke
218
+ Rake::Task['chef:install'].invoke
219
+ #Rake::Task['share:sync'].invoke
220
+
221
+ end
222
+
223
+ desc "Rebuild and Re-Chef the specified server."
224
+ task :rechef => [ "server:rebuild", "group:poll" ] do
225
+ server_name=ENV['SERVER_NAME']
226
+ raise "Please specify a SERVER_NAME." if server_name.nil?
227
+
228
+ configs=ChefInstaller.load_configs
229
+ configs.merge!(Util.load_configs)
230
+ hash=Util.hash_for_group(configs)
231
+ os_types=CloudServersVPC.os_types(hash)
232
+ configs["ssh_gateway_ip"]=hash["vpn-gateway"]
233
+ ChefInstaller.knife_readd_node(configs, server_name)
234
+ client_validation_key=ChefInstaller.client_validation_key(configs)
235
+ ChefInstaller.install_chef_client(configs, server_name, client_validation_key, os_types[server_name])
236
+
237
+ end
238
+
239
+ desc "Print help and usage information"
240
+ task :usage do
241
+
242
+ puts ""
243
+ puts "Cloud Toolkit Version: #{ChefVPCToolkit::Version::VERSION}"
244
+ puts ""
245
+ puts "The following tasks are available:"
246
+
247
+ puts %x{cd #{CHEF_VPC_PROJECT} && rake -T}
248
+ puts "----"
249
+ puts "Example commands:"
250
+ puts ""
251
+ puts "\t- Create a new cloud server group, upload cookbooks, install chef\n\ton all the nodes, sync share data and cookbooks."
252
+ puts ""
253
+ puts "\t\t$ rake create"
254
+
255
+ puts ""
256
+ puts "\t- List your currently running cloud server groups."
257
+ puts ""
258
+ puts "\t\t$ rake group:list"
259
+
260
+ puts ""
261
+ puts "\t- SSH into the current (most recently created) cloud server group"
262
+ puts ""
263
+ puts "\t\t$ rake ssh"
264
+
265
+ puts ""
266
+ puts "\t- SSH into a cloud server group with an ID of 3"
267
+ puts ""
268
+ puts "\t\t$ rake ssh GROUP_ID=3"
269
+
270
+ puts ""
271
+ puts "\t- Delete the cloud server group with an ID of 3"
272
+ puts ""
273
+ puts "\t\t$ rake group:delete GROUP_ID=3"
274
+
275
+ puts ""
276
+ puts "\t- Rebuild/Re-Chef a server in the most recently created cloud\n\tserver group"
277
+ puts ""
278
+ puts "\t\t$ rake rechef SERVER_NAME=db1"
279
+
280
+ puts ""
281
+
282
+ end
283
+
284
+ task :default => 'usage'
@@ -0,0 +1,174 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ require 'tempfile'
4
+
5
+ module ChefVPCToolkit
6
+
7
+ class CloudServersVPCTest < Test::Unit::TestCase
8
+
9
+ SERVER_GROUP_XML = %{
10
+ <?xml version="1.0" encoding="UTF-8"?>
11
+ <server-group>
12
+ <created-at type="datetime">2010-10-15T15:15:58-04:00</created-at>
13
+ <description>test description</description>
14
+ <domain-name>mydomain.net</domain-name>
15
+ <historical type="boolean">false</historical>
16
+ <id type="integer">1759</id>
17
+ <last-used-ip-address>172.19.0.2</last-used-ip-address>
18
+ <name>test</name>
19
+ <owner-name>dan.prince</owner-name>
20
+ <updated-at type="datetime">2010-10-15T15:15:58-04:00</updated-at>
21
+ <user-id type="integer">3</user-id>
22
+ <vpn-network>172.19.0.0</vpn-network>
23
+ <vpn-subnet>255.255.128.0</vpn-subnet>
24
+ <servers type="array">
25
+ <server>
26
+ <account-id type="integer">3</account-id>
27
+ <cloud-server-id-number type="integer">1</cloud-server-id-number>
28
+ <created-at type="datetime">2010-10-15T15:15:58-04:00</created-at>
29
+ <description>login1</description>
30
+ <error-message nil="true"></error-message>
31
+ <external-ip-addr>184.106.205.120</external-ip-addr>
32
+ <flavor-id type="integer">4</flavor-id>
33
+ <historical type="boolean">false</historical>
34
+ <id type="integer">5513</id>
35
+ <image-id type="integer">14</image-id>
36
+ <internal-ip-addr>10.179.107.203</internal-ip-addr>
37
+ <name>login1</name>
38
+ <openvpn-server type="boolean">true</openvpn-server>
39
+ <retry-count type="integer">0</retry-count>
40
+ <server-group-id type="integer">1759</server-group-id>
41
+ <status>Online</status>
42
+ <updated-at type="datetime">2010-10-15T15:18:22-04:00</updated-at>
43
+ <vpn-network-interfaces type="array"/>
44
+ </server>
45
+ <server>
46
+ <account-id type="integer">3</account-id>
47
+ <cloud-server-id-number type="integer">2</cloud-server-id-number>
48
+ <created-at type="datetime">2010-10-15T15:15:58-04:00</created-at>
49
+ <description>test1</description>
50
+ <error-message nil="true"></error-message>
51
+ <external-ip-addr>184.106.205.121</external-ip-addr>
52
+ <flavor-id type="integer">49</flavor-id>
53
+ <historical type="boolean">false</historical>
54
+ <id type="integer">5513</id>
55
+ <image-id type="integer">49</image-id>
56
+ <internal-ip-addr>10.179.107.204</internal-ip-addr>
57
+ <name>test1</name>
58
+ <openvpn-server type="boolean">false</openvpn-server>
59
+ <retry-count type="integer">0</retry-count>
60
+ <server-group-id type="integer">1759</server-group-id>
61
+ <status>Online</status>
62
+ <updated-at type="datetime">2010-10-15T15:18:22-04:00</updated-at>
63
+ <vpn-network-interfaces type="array"/>
64
+ </server>
65
+ </servers>
66
+ </server-group>
67
+ }
68
+
69
+ def test_os_types
70
+
71
+ #response = mock()
72
+ #response.stubs(:code => "200", :body => json_response)
73
+
74
+ #@conn.stubs(:csreq).returns(response)
75
+ hash=CloudServersVPC.server_group_hash(SERVER_GROUP_XML)
76
+ os_types=CloudServersVPC.os_types(hash)
77
+
78
+ assert_equal 2, os_types.size
79
+ assert_equal "rhel", os_types["login1"]
80
+ assert_equal "ubuntu", os_types["test1"]
81
+
82
+ end
83
+
84
+ def test_server_names
85
+
86
+ hash=CloudServersVPC.server_group_hash(SERVER_GROUP_XML)
87
+ names=CloudServersVPC.server_names(hash)
88
+
89
+ assert_equal 2, names.size
90
+ assert names.include?("login1")
91
+ assert names.include?("test1")
92
+
93
+ end
94
+
95
+ def test_print_server_group
96
+
97
+ hash=CloudServersVPC.server_group_hash(SERVER_GROUP_XML)
98
+ tmp = Tempfile.open('chef-cloud-toolkit')
99
+ begin
100
+ $stdout = tmp
101
+ CloudServersVPC.print_server_group(hash)
102
+ tmp.flush
103
+ output=IO.read(tmp.path)
104
+ $stdout = STDOUT
105
+ assert output =~ /login1/
106
+ assert output =~ /test1/
107
+ assert output =~ /184.106.205.120/
108
+ ensure
109
+ $stdout = STDOUT
110
+ end
111
+
112
+ end
113
+
114
+ def test_most_recent_server_group_hash
115
+
116
+ tmp_dir=TmpDir.new_tmp_dir
117
+ File.open("#{tmp_dir}/5.xml", 'w') do |f|
118
+ f.write(SERVER_GROUP_XML)
119
+ end
120
+
121
+ hash=CloudServersVPC.most_recent_server_group_hash(File.join(tmp_dir, '*.xml'))
122
+
123
+ assert_equal "mydomain.net", hash["domain-name"]
124
+ assert_equal "1759", hash["id"]
125
+ assert_equal 2, hash["servers"].size
126
+
127
+ end
128
+
129
+ def test_server_group_xml_for_id
130
+
131
+ tmp_dir=TmpDir.new_tmp_dir
132
+ File.open("#{tmp_dir}/5.xml", 'w') do |f|
133
+ f.write(SERVER_GROUP_XML)
134
+ end
135
+
136
+ configs={
137
+ "cloud_servers_vpc_url" => "http://localhost/",
138
+ "cloud_servers_vpc_username" => "admin",
139
+ "cloud_servers_vpc_password" => "test123"
140
+ }
141
+ HttpUtil.stubs(:get).returns(SERVER_GROUP_XML)
142
+ xml=CloudServersVPC.server_group_xml_for_id(configs, File.join(tmp_dir, '*.xml'))
143
+ assert_not_nil xml
144
+ xml=CloudServersVPC.server_group_xml_for_id(configs, File.join(tmp_dir, '*.xml'),"1759")
145
+ assert_not_nil xml
146
+
147
+ end
148
+
149
+ def test_load_public_key
150
+
151
+ key=CloudServersVPC.load_public_key
152
+ assert_not_nil key
153
+
154
+ end
155
+
156
+ def test_rebuild
157
+
158
+ response={}
159
+ response.stubs(:code).returns('200')
160
+ HttpUtil.stubs(:post).returns(response)
161
+
162
+ hash=CloudServersVPC.server_group_hash(SERVER_GROUP_XML)
163
+
164
+ assert_raises(RuntimeError) do
165
+ CloudServersVPC.rebuild(hash, "login1")
166
+ end
167
+
168
+ assert "200", CloudServersVPC.rebuild(hash, "test1").code
169
+
170
+ end
171
+
172
+ end
173
+
174
+ end