chef-vpc-toolkit 2.1.0 → 2.2.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.
@@ -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