chef-vpc-toolkit 2.0.0

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.
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