chef-vpc-toolkit 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,113 @@
1
+ module ChefVPCToolkit
2
+
3
+ module CloudServersVPC
4
+
5
+ class Server
6
+
7
+ attr_accessor :id
8
+ attr_accessor :name
9
+ attr_accessor :description
10
+ attr_accessor :external_ip_addr
11
+ attr_accessor :internal_ip_addr
12
+ attr_accessor :cloud_server_id_number
13
+ attr_accessor :flavor_id
14
+ attr_accessor :image_id
15
+ attr_accessor :server_group_id
16
+ attr_accessor :openvpn_server
17
+ attr_accessor :retry_count
18
+ attr_accessor :error_message
19
+ attr_accessor :status
20
+
21
+ def initialize(options={})
22
+ @id=options[:id].to_i
23
+ @name=options[:name]
24
+ @description=options[:description] or @description=@name
25
+ @external_ip_addr=options[:external_ip_addr]
26
+ @internal_ip_addr=options[:internal_ip_addr]
27
+ @cloud_server_id_number=options[:cloud_server_id_number].to_i
28
+ @flavor_id=options[:flavor_id].to_i
29
+ @image_id=options[:image_id].to_i
30
+ @server_group_id=options[:server_group_id].to_i
31
+ @openvpn_server = [true, "true"].include?(options[:openvpn_server])
32
+ @retry_count=options[:retry_count].to_i or 0
33
+ @error_message=options[:error_message]
34
+ @status=options[:status]
35
+ end
36
+
37
+ def openvpn_server?
38
+ return @openvpn_server
39
+ end
40
+
41
+ def to_xml
42
+
43
+ xml = Builder::XmlMarkup.new
44
+ xml.tag! "server" do |server|
45
+ server.id(@id)
46
+ server.name(@name)
47
+ server.description(@description)
48
+ server.status(@status) if @status
49
+ server.tag! "external-ip-addr", @external_ip_addr if @external_ip_addr
50
+ server.tag! "internal-ip-addr", @internal_ip_addr if @internal_ip_addr
51
+ server.tag! "cloud-server-id-number", @cloud_server_id_number if @cloud_server_id_number
52
+ server.tag! "flavor-id", @flavor_id
53
+ server.tag! "image-id", @image_id
54
+ server.tag! "server-group-id", @server_group_id
55
+ server.tag! "openvpn-server", "true" if openvpn_server?
56
+ server.tag! "error-message", @error_message if @error_message
57
+ end
58
+ xml.target!
59
+
60
+ end
61
+
62
+ def self.from_xml(xml)
63
+
64
+ server=nil
65
+ dom = REXML::Document.new(xml)
66
+ REXML::XPath.each(dom, "/*") do |sg_xml|
67
+
68
+ server=Server.new(
69
+ :id => XMLUtil.element_text(sg_xml, "id").to_i,
70
+ :name => XMLUtil.element_text(sg_xml, "name"),
71
+ :flavor_id => XMLUtil.element_text(sg_xml, "flavor-id"),
72
+ :image_id => XMLUtil.element_text(sg_xml, "image-id"),
73
+ :description => XMLUtil.element_text(sg_xml, "description"),
74
+ :cloud_server_id_number => XMLUtil.element_text(sg_xml, "cloud-server-id-number"),
75
+ :description => XMLUtil.element_text(sg_xml, "description"),
76
+ :external_ip_addr => XMLUtil.element_text(sg_xml, "external-ip-addr"),
77
+ :internal_ip_addr => XMLUtil.element_text(sg_xml, "internal-ip-addr"),
78
+ :server_group_id => XMLUtil.element_text(sg_xml, "server-group-id"),
79
+ :openvpn_server => XMLUtil.element_text(sg_xml, "openvpn_server"),
80
+ :retry_count => XMLUtil.element_text(sg_xml, "retry-count"),
81
+ :error_message => XMLUtil.element_text(sg_xml, "error-message"),
82
+ :status => XMLUtil.element_text(sg_xml, "status")
83
+ )
84
+ end
85
+
86
+ server
87
+
88
+ end
89
+
90
+ def rebuild
91
+
92
+ raise "Error: Rebuilding the OpenVPN server is not supported at this time." if openvpn_server?
93
+
94
+ Connection.post("/servers/#{@id}/rebuild", {})
95
+
96
+ end
97
+
98
+ def delete
99
+ Connection.delete("/servers/#{@id}.xml")
100
+ end
101
+
102
+ def self.create(server)
103
+
104
+ xml=Connection.post("/servers.xml", server.to_xml)
105
+ server=Server.from_xml(xml)
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,387 @@
1
+ require 'json'
2
+ require 'builder'
3
+ require 'fileutils'
4
+ require 'rexml/document'
5
+ require 'rexml/xpath'
6
+
7
+ module ChefVPCToolkit
8
+
9
+ module CloudServersVPC
10
+
11
+ class ServerGroup
12
+
13
+ @@data_dir=File.join(CHEF_VPC_PROJECT, "tmp", "server_groups")
14
+
15
+ def self.data_dir
16
+ @@data_dir
17
+ end
18
+
19
+ def self.data_dir=(dir)
20
+ @@data_dir=dir
21
+ end
22
+
23
+ CONFIG_FILE = CHEF_VPC_PROJECT + File::SEPARATOR + "config" + File::SEPARATOR + "server_group.json"
24
+
25
+ attr_accessor :id
26
+ attr_accessor :name
27
+ attr_accessor :description
28
+ attr_accessor :domain_name
29
+ attr_accessor :vpn_network
30
+ attr_accessor :vpn_subnet
31
+ attr_accessor :owner_name
32
+
33
+ attr_reader :ssh_public_keys
34
+
35
+ def initialize(options={})
36
+ @id=options[:id]
37
+ @name=options[:name]
38
+ @description=options[:description]
39
+ @domain_name=options[:domain_name]
40
+ @vpn_network=options[:vpn_network] or @vpn_network="172.19.0.0"
41
+ @vpn_subnet=options[:vpn_subnet] or @vpn_subnet="255.255.128.0"
42
+ @owner_name=options[:owner_name] or @owner_name=ENV['USER']
43
+
44
+ @servers=[]
45
+ @ssh_public_keys=[]
46
+ end
47
+
48
+ def server(name)
49
+ @servers.select {|s| s.name == name}[0] if @servers.size > 0
50
+ end
51
+
52
+ def servers
53
+ @servers
54
+ end
55
+
56
+ def vpn_gateway_name
57
+ @servers.select {|s| s.openvpn_server? }[0].name if @servers.size > 0
58
+ end
59
+
60
+ def vpn_gateway_ip
61
+ @servers.select {|s| s.openvpn_server? }[0].external_ip_addr if @servers.size > 0
62
+ end
63
+
64
+ def ssh_public_keys
65
+ @ssh_public_keys
66
+ end
67
+
68
+ # generate a Server Group XML from server_group.json
69
+ def self.from_json_config(json)
70
+
71
+ json_hash=JSON.parse(json)
72
+
73
+ sg=ServerGroup.new(
74
+ :name => json_hash["name"],
75
+ :description => json_hash["description"],
76
+ :domain_name => json_hash["domain_name"],
77
+ :vpn_network => json_hash["vpn_network"],
78
+ :vpn_subnet => json_hash["vpn_subnet"]
79
+ )
80
+ json_hash["servers"].each_pair do |server_name, server_config|
81
+ sg.servers << Server.new(
82
+ :name => server_name,
83
+ :description => server_config["description"],
84
+ :flavor_id => server_config["flavor_id"],
85
+ :image_id => server_config["image_id"],
86
+ :openvpn_server => server_config["openvpn_server"]
87
+ )
88
+ end
89
+
90
+ # automatically add a key for the current user
91
+ sg.ssh_public_keys << SshPublicKey.new(
92
+ :description => "#{ENV['USER']}'s public key",
93
+ :public_key => Util.load_public_key
94
+
95
+ )
96
+
97
+ return sg
98
+
99
+ end
100
+
101
+ def to_xml
102
+
103
+ xml = Builder::XmlMarkup.new
104
+ xml.tag! "server-group" do |sg|
105
+ sg.id(@id)
106
+ sg.name(@name)
107
+ sg.description(@description)
108
+ sg.tag! "owner-name", @owner_name
109
+ sg.tag! "domain-name", @domain_name
110
+ sg.tag! "vpn-network", @vpn_network
111
+ sg.tag! "vpn-subnet", @vpn_subnet
112
+ sg.servers("type" => "array") do |xml_servers|
113
+ self.servers.each do |server|
114
+ xml_servers.server do |xml_server|
115
+ xml_server.id(server.id)
116
+ xml_server.name(server.name)
117
+ xml_server.description(server.description)
118
+ xml_server.tag! "flavor-id", server.flavor_id
119
+ xml_server.tag! "image-id", server.image_id
120
+ xml_server.tag! "cloud-server-id-number", server.cloud_server_id_number if server.cloud_server_id_number
121
+ xml_server.tag! "status", server.status if server.status
122
+ xml_server.tag! "external-ip-addr", server.external_ip_addr if server.external_ip_addr
123
+ xml_server.tag! "internal-ip-addr", server.internal_ip_addr if server.internal_ip_addr
124
+ xml_server.tag! "error-message", server.error_message if server.error_message
125
+ xml_server.tag! "retry-count", server.retry_count if server.retry_count
126
+ if server.openvpn_server?
127
+ xml_server.tag! "openvpn-server", "true", { "type" => "boolean"}
128
+ end
129
+ end
130
+ end
131
+ end
132
+ sg.tag! "ssh-public-keys", { "type" => "array"} do |xml_ssh_pub_keys|
133
+ self.ssh_public_keys.each do |ssh_public_key|
134
+ xml_ssh_pub_keys.tag! "ssh-public-key" do |xml_ssh_pub_key|
135
+ xml_ssh_pub_key.description ssh_public_key.description
136
+ xml_ssh_pub_key.tag! "public-key", ssh_public_key.public_key
137
+ end
138
+ end
139
+ end
140
+ end
141
+ xml.target!
142
+
143
+ end
144
+
145
+ def self.from_xml(xml)
146
+
147
+ sg=nil
148
+ dom = REXML::Document.new(xml)
149
+ REXML::XPath.each(dom, "/server-group") do |sg_xml|
150
+ sg=ServerGroup.new(
151
+ :name => XMLUtil.element_text(sg_xml, "name"),
152
+ :id => XMLUtil.element_text(sg_xml, "id").to_i,
153
+ :domain_name => XMLUtil.element_text(sg_xml, "domain-name"),
154
+ :description => XMLUtil.element_text(sg_xml, "description"),
155
+ :vpn_network => XMLUtil.element_text(sg_xml, "vpn-network"),
156
+ :vpn_subnet => XMLUtil.element_text(sg_xml, "vpn-subnet")
157
+ )
158
+ REXML::XPath.each(dom, "//server") do |server_xml|
159
+
160
+ server=Server.new(
161
+ :id => XMLUtil.element_text(server_xml, "id").to_i,
162
+ :name => XMLUtil.element_text(server_xml, "name"),
163
+ :cloud_server_id_number => XMLUtil.element_text(server_xml, "cloud-server-id-number"),
164
+ :status => XMLUtil.element_text(server_xml, "status"),
165
+ :external_ip_addr => XMLUtil.element_text(server_xml, "external-ip-addr"),
166
+ :internal_ip_addr => XMLUtil.element_text(server_xml, "internal-ip-addr"),
167
+ :error_message => XMLUtil.element_text(server_xml, "error-message"),
168
+ :image_id => XMLUtil.element_text(server_xml, "image-id"),
169
+ :flavor_id => XMLUtil.element_text(server_xml, "flavor-id"),
170
+ :retry_count => XMLUtil.element_text(server_xml, "retry-count"),
171
+ :openvpn_server => XMLUtil.element_text(server_xml, "openvpn-server")
172
+ )
173
+ sg.servers << server
174
+ end
175
+ end
176
+
177
+ sg
178
+
179
+ end
180
+
181
+ def pretty_print
182
+
183
+ puts "Group ID: #{@id}"
184
+ puts "name: #{@name}"
185
+ puts "description: #{@description}"
186
+ puts "domain name: #{@domain_name}"
187
+ puts "VPN gateway IP: #{self.vpn_gateway_ip}"
188
+ puts "Servers:"
189
+ servers.each do |server|
190
+ puts "\tname: #{server.name} (id: #{server.id})"
191
+ puts "\tstatus: #{server.status}"
192
+ if server.openvpn_server?
193
+ puts "\tOpenVPN server: #{server.openvpn_server?}"
194
+ end
195
+ if server.error_message then
196
+ puts "\tlast error message: #{server.error_message}"
197
+ end
198
+ puts "\t--"
199
+ end
200
+
201
+ end
202
+
203
+ def server_names
204
+
205
+ names=[]
206
+
207
+ servers.each do |server|
208
+ if block_given? then
209
+ yield server.name
210
+ else
211
+ names << server.name
212
+ end
213
+ end
214
+
215
+ names
216
+
217
+ end
218
+
219
+ def cache_to_disk
220
+ FileUtils.mkdir_p(@@data_dir)
221
+ File.open(File.join(@@data_dir, "#{@id}.xml"), 'w') do |f|
222
+ f.chmod(0600)
223
+ f.write(self.to_xml)
224
+ end
225
+ end
226
+
227
+ def delete
228
+
229
+ Connection.delete("/server_groups/#{@id}.xml")
230
+ out_file=File.join(@@data_dir, "#{@id}.xml")
231
+ File.delete(out_file) if File.exists?(out_file)
232
+
233
+ end
234
+
235
+ # Poll the server group until it is online.
236
+ # :timeout - max number of seconds to wait before raising an exception.
237
+ # Defaults to 1500
238
+ def poll_until_online(options={})
239
+
240
+ timeout=options[:timeout] or timeout = ENV['TIMEOUT']
241
+ if timeout.nil? or timeout.empty? then
242
+ timeout=1500 # defaults to 25 minutes
243
+ end
244
+
245
+ online = false
246
+ count=0
247
+ until online or (count*20) >= timeout.to_i do
248
+ count+=1
249
+ begin
250
+ sg=ServerGroup.fetch(:id => @id, :source => "remote")
251
+
252
+ online=true
253
+ sg.servers.each do |server|
254
+ if ["Pending", "Rebuilding"].include?(server.status) then
255
+ online=false
256
+ end
257
+ if server.status == "Failed" then
258
+ raise "Failed to create server group with the following message: #{server.error_message}"
259
+ end
260
+ end
261
+ if not online
262
+ yield sg if block_given?
263
+ sleep 20
264
+ end
265
+ rescue EOFError
266
+ end
267
+ end
268
+ if (count*20) >= timeout.to_i then
269
+ raise "Timeout waiting for server groups to come online."
270
+ end
271
+
272
+ end
273
+
274
+ def self.create(sg)
275
+
276
+ xml=Connection.post("/server_groups.xml", sg.to_xml)
277
+ sg=ServerGroup.from_xml(xml)
278
+ sg.cache_to_disk
279
+ sg
280
+
281
+ end
282
+
283
+ # Fetch a server group. The following options are available:
284
+ #
285
+ # :id - The ID of the server group to fetch. Defaults to ENV['GROUP_ID']
286
+ # :source - valid options are 'remote' and 'cache'
287
+ def self.fetch(options={})
288
+
289
+ source = options[:source] or source = "remote"
290
+ id=options[:id] or id = ENV['GROUP_ID']
291
+ if id.nil? then
292
+ group=ServerGroup.most_recent
293
+ raise "No server group files exist." if group.nil?
294
+ id=group.id
295
+ end
296
+
297
+ if source == "remote" then
298
+ xml=Connection.get("/server_groups/#{id}.xml")
299
+ ServerGroup.from_xml(xml)
300
+ elsif source == "cache" then
301
+ out_file=File.join(@@data_dir, "#{id}.xml")
302
+ raise "No server group files exist." if not File.exists?(out_file)
303
+ ServerGroup.from_xml(IO.read(out_file))
304
+ else
305
+ raise "Invalid fetch :source specified."
306
+ end
307
+
308
+ end
309
+
310
+ # :source - valid options are 'remote' and 'cache'
311
+ def self.list(options={})
312
+
313
+ source = options[:source] or source = "cache"
314
+ server_groups=[]
315
+ if source == "remote" then
316
+ xml=Connection.get("/server_groups.xml")
317
+ dom = REXML::Document.new(xml)
318
+ REXML::XPath.each(dom, "//server-group") do |group_xml|
319
+ server_groups << ServerGroup.from_xml(group_xml.to_s)
320
+ end
321
+ else
322
+ Dir[File.join(ServerGroup.data_dir, '*.xml')].each do |file|
323
+ server_groups << ServerGroup.from_xml(IO.read(file))
324
+ end
325
+ end
326
+
327
+ server_groups
328
+
329
+ end
330
+
331
+ def self.most_recent
332
+ server_groups=[]
333
+ Dir[File.join(@@data_dir, "*.xml")].each do |file|
334
+ server_groups << ServerGroup.from_xml(IO.read(file))
335
+ end
336
+ if server_groups.size > 0 then
337
+ server_groups.sort { |a,b| b.id <=> a.id }[0]
338
+ else
339
+ nil
340
+ end
341
+ end
342
+
343
+ def os_types
344
+
345
+ os_types={}
346
+ self.servers.each do |server|
347
+ os_type = case server.image_id
348
+ when 51 # Centos 5.5
349
+ "centos"
350
+ when 187811 # Centos 5.4
351
+ "centos"
352
+ when 71 # Fedora 14
353
+ "fedora"
354
+ when 53 # Fedora 13
355
+ "fedora"
356
+ when 17 # Fedora 12
357
+ "fedora"
358
+ when 14 # RHEL 5.4
359
+ "rhel"
360
+ when 62 # RHEL 5.5
361
+ "rhel"
362
+ when 69 # Ubuntu 10.10
363
+ "ubuntu"
364
+ when 49 # Ubuntu 10.04
365
+ "ubuntu"
366
+ when 14362 # Ubuntu 9.10
367
+ "ubuntu"
368
+ when 8 # Ubuntu 9.04
369
+ "ubuntu"
370
+ else
371
+ "unknown"
372
+ end
373
+ if block_given? then
374
+ yield server.name, os_type
375
+ else
376
+ os_types.store(server.name, os_type)
377
+ end
378
+ end
379
+ os_types
380
+
381
+ end
382
+
383
+ end
384
+
385
+ end
386
+
387
+ end