kytoon 1.2.5 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -0
- data/README.md +8 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/config/server_group_libvirt.json +7 -0
- data/lib/kytoon/providers/libvirt/server_group.rb +50 -4
- data/lib/kytoon/providers/openstack/server_group.rb +149 -28
- data/lib/kytoon/util.rb +6 -0
- metadata +4 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
* Mon Dec 13 2012 Dan Prince <dprince@redhat.com> - 1.3.0
|
2
|
+
-OpenStack: Switch to Fog.
|
3
|
+
-OpenStack: Add support for automatic floating IP configuration via
|
4
|
+
'assign_floating_ip' in server group json files.
|
5
|
+
-OpenStack: Add support for security group names.
|
6
|
+
-OpenStack: Add endpoint configs for region, service_type, service_name.
|
7
|
+
-OpenStack: Configure ssh access within the server group.
|
8
|
+
-Libvirt: grep correct dnsmasq leases file (use network name)
|
9
|
+
-Libvirt: fix libvirt_use_sudo option (string conversion)
|
10
|
+
-Libvirt: Configure ssh access within the server group.
|
11
|
+
|
1
12
|
* Mon Nov 26 2012 Dan Prince <dprince@redhat.com> - 1.2.5
|
2
13
|
- Libvirt: ping test instances to ensure they have IPs before
|
3
14
|
trying to configure hosts, etc.
|
data/README.md
CHANGED
@@ -25,10 +25,13 @@ Inspired by and based on the Chef VPC Toolkit.
|
|
25
25
|
|
26
26
|
## Installation
|
27
27
|
|
28
|
-
|
28
|
+
Quick install on Fedora:
|
29
29
|
|
30
|
+
yum install -y rubygems ruby-devel gcc gcc-c++ libxslt-devel
|
30
31
|
gem install kytoon
|
31
32
|
|
33
|
+
*NOTE: Kytoon has been tested with Fog 1.8.0+ only (1.9.0 will be required to work with Rackspace's OpenStack Cloud)
|
34
|
+
|
32
35
|
Create a .kytoon.conf file in your $HOME directory.
|
33
36
|
|
34
37
|
# The default group type.
|
@@ -41,9 +44,13 @@ Create a .kytoon.conf file in your $HOME directory.
|
|
41
44
|
openstack_password: <password>
|
42
45
|
openstack_network_name: public # Optional: defaults to public
|
43
46
|
openstack_keypair_name: < keyname > # Optional: file injection via personalities is the default
|
47
|
+
openstack_security_groups: ['', ''] # Optional: Array of security group names
|
44
48
|
openstack_ip_type: 4 # IP type (4 or 6): defaults to 4
|
45
49
|
openstack_build_timeout: 480 # Server build timeout. Defaults to: 480
|
46
50
|
openstack_ping_timeout: 60 # Server build timeout. Defaults to: 60
|
51
|
+
openstack_service_name: < name > # Optional: default is None... some clouds have multiple 'compute' services so this may be required
|
52
|
+
openstack_service_type: compute # Optional: default is 'compute'
|
53
|
+
openstack_region: < region name > # Optional
|
47
54
|
|
48
55
|
# Libvirt settings
|
49
56
|
# Whether commands to create local group should use sudo
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
@@ -4,9 +4,16 @@
|
|
4
4
|
{
|
5
5
|
"hostname": "nova1",
|
6
6
|
"memory": "1",
|
7
|
+
"original_xml": "/home/dprince/f17.xml",
|
8
|
+
"create_cow": "true"
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"hostname": "login",
|
12
|
+
"memory": "1",
|
7
13
|
"gateway": "true",
|
8
14
|
"original_xml": "/home/dprince/f17.xml",
|
9
15
|
"create_cow": "true"
|
10
16
|
}
|
17
|
+
|
11
18
|
]
|
12
19
|
}
|
@@ -61,7 +61,7 @@ class ServerGroup
|
|
61
61
|
json_hash=JSON.parse(json)
|
62
62
|
|
63
63
|
configs = Util.load_configs
|
64
|
-
use_sudo = ENV['LIBVIRT_USE_SUDO'] || configs['libvirt_use_sudo']
|
64
|
+
use_sudo = ENV['LIBVIRT_USE_SUDO'] || configs['libvirt_use_sudo'].to_s
|
65
65
|
|
66
66
|
sg=ServerGroup.new(
|
67
67
|
:id => json_hash["id"],
|
@@ -138,11 +138,25 @@ class ServerGroup
|
|
138
138
|
end
|
139
139
|
out_file=File.join(@@data_dir, "#{@id}.json")
|
140
140
|
File.delete(out_file) if File.exists?(out_file)
|
141
|
+
|
142
|
+
#cleanup ssh keys
|
143
|
+
private_ssh_key = File.join(@@data_dir, "#{@id}_id_rsa")
|
144
|
+
public_ssh_key = File.join(@@data_dir, "#{@id}_id_rsa.pub")
|
145
|
+
[private_ssh_key, public_ssh_key].each do |file|
|
146
|
+
File.delete(file) if File.exists?(file)
|
147
|
+
end
|
148
|
+
|
141
149
|
end
|
142
150
|
|
143
151
|
def self.create(sg)
|
144
152
|
|
145
153
|
ssh_public_key = Kytoon::Util.load_public_key
|
154
|
+
|
155
|
+
base_key_name=File.join(@@data_dir, "#{sg.id}_id_rsa")
|
156
|
+
Kytoon::Util.generate_ssh_keypair(base_key_name)
|
157
|
+
private_ssh_key=IO.read(base_key_name)
|
158
|
+
public_ssh_key=IO.read(base_key_name + ".pub")
|
159
|
+
|
146
160
|
sudo = sg.use_sudo =~ /(true|t|yes|y|1)$/i ? "sudo" : ""
|
147
161
|
hosts_file_data = "127.0.0.1\tlocalhost localhost.localdomain\n"
|
148
162
|
sg.servers.each do |server|
|
@@ -158,6 +172,31 @@ class ServerGroup
|
|
158
172
|
end
|
159
173
|
|
160
174
|
puts "Copying hosts files..."
|
175
|
+
|
176
|
+
gateway_ssh_config = %{
|
177
|
+
[ -d .ssh ] || mkdir .ssh
|
178
|
+
cat > .ssh/id_rsa <<-EOF_CAT
|
179
|
+
#{private_ssh_key}
|
180
|
+
EOF_CAT
|
181
|
+
chmod 600 .ssh/id_rsa
|
182
|
+
cat > .ssh/id_rsa.pub <<-EOF_CAT
|
183
|
+
#{public_ssh_key}
|
184
|
+
EOF_CAT
|
185
|
+
chmod 600 .ssh/id_rsa.pub
|
186
|
+
cat > .ssh/config <<-EOF_CAT
|
187
|
+
StrictHostKeyChecking no
|
188
|
+
EOF_CAT
|
189
|
+
chmod 600 .ssh/config
|
190
|
+
}
|
191
|
+
|
192
|
+
node_ssh_config= %{
|
193
|
+
[ -d .ssh ] || mkdir .ssh
|
194
|
+
cat > .ssh/authorized_keys <<-EOF_CAT
|
195
|
+
#{public_ssh_key}
|
196
|
+
EOF_CAT
|
197
|
+
chmod 600 .ssh/authorized_keys
|
198
|
+
}
|
199
|
+
|
161
200
|
#now that we have IP info copy hosts files into the servers
|
162
201
|
sg.servers.each do |server|
|
163
202
|
ping_test(server['ip_address'])
|
@@ -169,6 +208,7 @@ hostname "#{server['hostname']}"
|
|
169
208
|
if [ -f /etc/sysconfig/network ]; then
|
170
209
|
sed -e "s|^HOSTNAME.*|HOSTNAME=#{server['hostname']}|" -i /etc/sysconfig/network
|
171
210
|
fi
|
211
|
+
#{server['gateway'] == 'true' ? gateway_ssh_config : node_ssh_config}
|
172
212
|
}, server['ip_address']) do |ok, out|
|
173
213
|
if not ok
|
174
214
|
puts out
|
@@ -304,7 +344,8 @@ if [ -n "$LV_ROOT" ]; then
|
|
304
344
|
mount $LV_ROOT / : \
|
305
345
|
sh "/bin/mkdir -p /root/.ssh" : \
|
306
346
|
write-append /root/.ssh/authorized_keys "#{ssh_public_key}" : \
|
307
|
-
sh "/bin/chmod
|
347
|
+
sh "/bin/chmod 700 /root/.ssh" : \
|
348
|
+
sh "/bin/chmod 600 /root/.ssh/authorized_keys"
|
308
349
|
fi
|
309
350
|
|
310
351
|
#{sudo} virsh setmaxmem #{domain_name} #{instance_memory}
|
@@ -320,17 +361,22 @@ fi
|
|
320
361
|
|
321
362
|
# lookup server IP here...
|
322
363
|
mac_addr = nil
|
364
|
+
network_name = nil
|
323
365
|
dom_xml = %x{#{sudo} virsh --connect=qemu:///system dumpxml #{domain_name}}
|
324
366
|
dom = REXML::Document.new(dom_xml)
|
325
367
|
REXML::XPath.each(dom, "//interface/mac") do |interface_xml|
|
326
368
|
mac_addr = interface_xml.attributes['address']
|
327
369
|
end
|
328
370
|
raise KytoonException, "Failed to lookup mac address for #{inst_name}" if mac_addr.nil?
|
371
|
+
REXML::XPath.each(dom, "//interface/source") do |interface_xml|
|
372
|
+
network_name = interface_xml.attributes['network']
|
373
|
+
end
|
374
|
+
raise KytoonException, "Failed to lookup network name for #{inst_name}" if network_name.nil?
|
329
375
|
|
330
|
-
instance_ip = %x{grep -i #{mac_addr} /var/lib/libvirt/dnsmasq
|
376
|
+
instance_ip = %x{grep -i #{mac_addr} /var/lib/libvirt/dnsmasq/#{network_name}.leases | cut -d " " -f 3}.chomp
|
331
377
|
count = 0
|
332
378
|
until not instance_ip.empty? do
|
333
|
-
instance_ip = %x{grep -i #{mac_addr} /var/lib/libvirt/dnsmasq
|
379
|
+
instance_ip = %x{grep -i #{mac_addr} /var/lib/libvirt/dnsmasq/#{network_name}.leases | cut -d " " -f 3}.chomp
|
334
380
|
sleep 1
|
335
381
|
count += 1
|
336
382
|
if count >= 60 then
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'kytoon/util'
|
3
|
-
require '
|
3
|
+
require 'fog'
|
4
4
|
|
5
5
|
module Kytoon
|
6
6
|
|
@@ -26,10 +26,12 @@ class ServerGroup
|
|
26
26
|
|
27
27
|
attr_accessor :id
|
28
28
|
attr_accessor :name
|
29
|
+
attr_accessor :use_security_groups
|
29
30
|
|
30
31
|
def initialize(options={})
|
31
32
|
@id = options[:id] || Time.now.to_f
|
32
33
|
@name = options[:name]
|
34
|
+
@use_security_groups = options[:use_security_groups]
|
33
35
|
@servers=[]
|
34
36
|
end
|
35
37
|
|
@@ -52,7 +54,8 @@ class ServerGroup
|
|
52
54
|
|
53
55
|
sg=ServerGroup.new(
|
54
56
|
:id => json_hash["id"],
|
55
|
-
:name => json_hash["name"]
|
57
|
+
:name => json_hash["name"],
|
58
|
+
:use_security_groups => json_hash["use_security_groups"]
|
56
59
|
)
|
57
60
|
json_hash["servers"].each do |server_hash|
|
58
61
|
|
@@ -62,7 +65,11 @@ class ServerGroup
|
|
62
65
|
'image_ref' => server_hash['image_ref'],
|
63
66
|
'flavor_ref' => server_hash['flavor_ref'],
|
64
67
|
'keypair_name' => server_hash['keypair_name'],
|
68
|
+
'floating_ip' => server_hash['floating_ip'],
|
65
69
|
'gateway' => server_hash['gateway'] || "false",
|
70
|
+
'assign_floating_ip' => server_hash['assign_floating_ip'] || "false",
|
71
|
+
'floating_ip' => server_hash['floating_ip'] || nil,
|
72
|
+
'floating_ip_id' => server_hash['floating_ip_id'] || nil,
|
66
73
|
'ip_address' => server_hash['ip_address']
|
67
74
|
}
|
68
75
|
end
|
@@ -84,7 +91,7 @@ class ServerGroup
|
|
84
91
|
|
85
92
|
def server_names
|
86
93
|
|
87
|
-
names=[]
|
94
|
+
names=[]
|
88
95
|
|
89
96
|
servers.each do |server|
|
90
97
|
if block_given? then
|
@@ -103,10 +110,11 @@ class ServerGroup
|
|
103
110
|
sg_hash = {
|
104
111
|
'id' => @id,
|
105
112
|
'name' => @name,
|
113
|
+
'use_security_groups' => @use_security_groups,
|
106
114
|
'servers' => []
|
107
115
|
}
|
108
116
|
@servers.each do |server|
|
109
|
-
sg_hash['servers'] << {'id' => server['id'], 'hostname' => server['hostname'], 'image_ref' => server['image_ref'], 'gateway' => server['gateway'], 'flavor_ref' => server['flavor_ref'], 'ip_address' => server['ip_address']}
|
117
|
+
sg_hash['servers'] << {'id' => server['id'], 'hostname' => server['hostname'], 'image_ref' => server['image_ref'], 'gateway' => server['gateway'], 'flavor_ref' => server['flavor_ref'], 'ip_address' => server['ip_address'], 'floating_ip' => server['floating_ip'], 'floating_ip_id' => server['floating_ip_id'], 'assign_floating_ip' => server['assign_floating_ip']}
|
110
118
|
end
|
111
119
|
|
112
120
|
FileUtils.mkdir_p(@@data_dir)
|
@@ -118,23 +126,44 @@ class ServerGroup
|
|
118
126
|
|
119
127
|
def delete
|
120
128
|
servers.each do |server|
|
129
|
+
if server['assign_floating_ip'] == 'true' then
|
130
|
+
ServerGroup.release_floating_ip(server)
|
131
|
+
end
|
121
132
|
ServerGroup.destroy_instance(server['id'])
|
122
133
|
end
|
134
|
+
|
135
|
+
#cleanup ssh keys
|
136
|
+
private_ssh_key = File.join(@@data_dir, "#{@id}_id_rsa")
|
137
|
+
public_ssh_key = File.join(@@data_dir, "#{@id}_id_rsa.pub")
|
138
|
+
[private_ssh_key, public_ssh_key].each do |file|
|
139
|
+
File.delete(file) if File.exists?(file)
|
140
|
+
end
|
141
|
+
|
123
142
|
out_file=File.join(@@data_dir, "#{@id}.json")
|
124
143
|
File.delete(out_file) if File.exists?(out_file)
|
125
144
|
end
|
126
145
|
|
127
|
-
|
128
146
|
def self.create(sg)
|
129
147
|
|
130
148
|
hosts_file_data = "127.0.0.1\tlocalhost localhost.localdomain\n"
|
131
149
|
|
132
150
|
build_timeout = (Util.load_configs['openstack_build_timeout'] || 60).to_i
|
133
151
|
|
152
|
+
base_key_name=File.join(@@data_dir, "#{sg.id}_id_rsa")
|
153
|
+
Kytoon::Util.generate_ssh_keypair(base_key_name)
|
154
|
+
private_ssh_key=IO.read(base_key_name)
|
155
|
+
public_ssh_key=IO.read(base_key_name + ".pub")
|
156
|
+
|
134
157
|
sg.servers.each do |server|
|
135
158
|
server_id = create_instance(sg.id, server['hostname'], server['image_ref'], server['flavor_ref'], server['keypair_name']).id
|
136
|
-
|
137
159
|
server['id'] = server_id
|
160
|
+
|
161
|
+
if server['assign_floating_ip'] == 'true' then
|
162
|
+
floating_data = assign_floating_ip(server_id)
|
163
|
+
server['floating_ip_id'] = floating_data[0]
|
164
|
+
server['floating_ip'] = floating_data[1]
|
165
|
+
end
|
166
|
+
|
138
167
|
sg.cache_to_disk
|
139
168
|
end
|
140
169
|
|
@@ -143,7 +172,11 @@ class ServerGroup
|
|
143
172
|
ips = get_server_ips
|
144
173
|
sg.servers.each do |server|
|
145
174
|
server_ip = ips[server['id']]
|
146
|
-
server['
|
175
|
+
if server['assign_floating_ip'] == 'true' then
|
176
|
+
server['ip_address'] = server['floating_ip']
|
177
|
+
else
|
178
|
+
server['ip_address'] = server_ip
|
179
|
+
end
|
147
180
|
sg.cache_to_disk
|
148
181
|
hosts_file_data += "#{server_ip}\t#{server['hostname']}\n"
|
149
182
|
end
|
@@ -152,9 +185,33 @@ class ServerGroup
|
|
152
185
|
raise KytoonException, "Timeout building server group."
|
153
186
|
end
|
154
187
|
|
155
|
-
|
156
188
|
puts "Copying hosts files..."
|
157
|
-
|
189
|
+
|
190
|
+
gateway_ssh_config = %{
|
191
|
+
[ -d .ssh ] || mkdir .ssh
|
192
|
+
cat > .ssh/id_rsa <<-EOF_CAT
|
193
|
+
#{private_ssh_key}
|
194
|
+
EOF_CAT
|
195
|
+
chmod 600 .ssh/id_rsa
|
196
|
+
cat > .ssh/id_rsa.pub <<-EOF_CAT
|
197
|
+
#{public_ssh_key}
|
198
|
+
EOF_CAT
|
199
|
+
chmod 600 .ssh/id_rsa.pub
|
200
|
+
cat > .ssh/config <<-EOF_CAT
|
201
|
+
StrictHostKeyChecking no
|
202
|
+
EOF_CAT
|
203
|
+
chmod 600 .ssh/config
|
204
|
+
}
|
205
|
+
|
206
|
+
node_ssh_config= %{
|
207
|
+
[ -d .ssh ] || mkdir .ssh
|
208
|
+
cat > .ssh/authorized_keys <<-EOF_CAT
|
209
|
+
#{public_ssh_key}
|
210
|
+
EOF_CAT
|
211
|
+
chmod 600 .ssh/authorized_keys
|
212
|
+
}
|
213
|
+
|
214
|
+
# now that we have IP info copy hosts files into the servers
|
158
215
|
sg.servers.each do |server|
|
159
216
|
ping_test(server['ip_address'])
|
160
217
|
Kytoon::Util.remote_exec(%{
|
@@ -165,6 +222,7 @@ hostname "#{server['hostname']}"
|
|
165
222
|
if [ -f /etc/sysconfig/network ]; then
|
166
223
|
sed -e "s|^HOSTNAME.*|HOSTNAME=#{server['hostname']}|" -i /etc/sysconfig/network
|
167
224
|
fi
|
225
|
+
#{server['gateway'] == 'true' ? gateway_ssh_config : node_ssh_config}
|
168
226
|
}, server['ip_address']) do |ok, out|
|
169
227
|
if not ok
|
170
228
|
puts out
|
@@ -215,11 +273,15 @@ fi
|
|
215
273
|
def self.init_connection
|
216
274
|
configs = Util.load_configs
|
217
275
|
if @@connection.nil? then
|
218
|
-
|
219
|
-
:
|
220
|
-
:
|
221
|
-
:
|
222
|
-
:
|
276
|
+
@connection = Fog::Compute.new(
|
277
|
+
:provider => :openstack,
|
278
|
+
:openstack_auth_url => configs['openstack_url'],
|
279
|
+
:openstack_username => configs['openstack_username'],
|
280
|
+
:openstack_api_key => configs['openstack_password'],
|
281
|
+
:openstack_service_name => configs['openstack_service_name'],
|
282
|
+
:openstack_service_type => configs['openstack_service_type'],
|
283
|
+
:openstack_region => configs['openstack_region']
|
284
|
+
)
|
223
285
|
else
|
224
286
|
@@connection
|
225
287
|
end
|
@@ -227,24 +289,76 @@ fi
|
|
227
289
|
|
228
290
|
def self.create_instance(group_id, hostname, image_ref, flavor_ref, keypair_name)
|
229
291
|
|
230
|
-
ssh_public_key = Util.public_key_path
|
231
292
|
configs = Util.load_configs
|
232
|
-
|
233
293
|
conn = self.init_connection
|
234
294
|
|
235
295
|
options = {
|
236
296
|
:name => "#{group_id}_#{hostname}",
|
237
|
-
:
|
238
|
-
:
|
239
|
-
:personality => {ssh_public_key => "/root/.ssh/authorized_keys"},
|
240
|
-
:is_debug => true}
|
297
|
+
:image_ref => image_ref,
|
298
|
+
:flavor_ref => flavor_ref}
|
241
299
|
|
242
300
|
keypair_name = configs['openstack_keypair_name'] if keypair_name.nil?
|
301
|
+
security_groups = configs['openstack_security_groups']
|
302
|
+
if not security_groups.nil? and not security_groups.empty? then
|
303
|
+
options.store(:security_groups, security_groups)
|
304
|
+
end
|
243
305
|
if not keypair_name.nil? and not keypair_name.empty? then
|
244
306
|
options.store(:key_name, keypair_name)
|
307
|
+
else
|
308
|
+
options.store(:personality, [
|
309
|
+
{'path' => "/root/.ssh/authorized_keys",
|
310
|
+
'contents' => IO.read(Util.public_key_path)}])
|
311
|
+
end
|
312
|
+
|
313
|
+
server = conn.servers.create(options)
|
314
|
+
server
|
315
|
+
|
316
|
+
end
|
317
|
+
|
318
|
+
def self.assign_floating_ip(server_id)
|
319
|
+
|
320
|
+
conn = self.init_connection
|
321
|
+
|
322
|
+
data = conn.allocate_address.body
|
323
|
+
address_id = data['floating_ip']['id']
|
324
|
+
address_ip = data['floating_ip']['ip']
|
325
|
+
|
326
|
+
configs = Util.load_configs
|
327
|
+
network_name = configs['openstack_network_name'] || 'public'
|
328
|
+
|
329
|
+
# wait for instance to obtain fixed ip
|
330
|
+
1.upto(60) do
|
331
|
+
server = conn.servers.get(server_id)
|
332
|
+
if server.addresses and server.addresses[network_name] and server.addresses[network_name].detect {|a| a['version'] == self.default_ip_type} then
|
333
|
+
break
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
conn.associate_address(server_id, address_ip).body
|
338
|
+
[address_id, address_ip]
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
def self.release_floating_ip(server)
|
343
|
+
|
344
|
+
conn = self.init_connection
|
345
|
+
|
346
|
+
address_ip = server['floating_ip']
|
347
|
+
address_id = server['floating_ip_id']
|
348
|
+
|
349
|
+
conn.disassociate_address(server['id'], address_ip)
|
350
|
+
|
351
|
+
# wait for address to disassociate (instance_id should be nil)
|
352
|
+
1.upto(30) do
|
353
|
+
floating_ips = conn.list_all_addresses.body['floating_ips']
|
354
|
+
break if floating_ips.detect {|f| f['id'] == address_id and f['instance_id' == nil]}
|
245
355
|
end
|
246
356
|
|
247
|
-
|
357
|
+
begin
|
358
|
+
conn.release_address(address_id)
|
359
|
+
rescue Fog::Compute::OpenStack::NotFound
|
360
|
+
puts "Unable to release IP address #{address_ip}: Not Found."
|
361
|
+
end
|
248
362
|
|
249
363
|
end
|
250
364
|
|
@@ -265,12 +379,14 @@ fi
|
|
265
379
|
until all_active do
|
266
380
|
all_active = true
|
267
381
|
conn.servers.each do |server|
|
268
|
-
server
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
382
|
+
if ips[server.id].nil? then
|
383
|
+
server = conn.servers.get(server.id)
|
384
|
+
if server.state == 'ACTIVE' then
|
385
|
+
addresses = server.addresses[network_name].select {|a| a['version'] == self.default_ip_type}
|
386
|
+
ips[server.id] = addresses[0]['addr']
|
387
|
+
else
|
388
|
+
all_active = false
|
389
|
+
end
|
274
390
|
end
|
275
391
|
end
|
276
392
|
end
|
@@ -302,7 +418,12 @@ fi
|
|
302
418
|
def self.destroy_instance(uuid)
|
303
419
|
begin
|
304
420
|
conn = self.init_connection
|
305
|
-
conn.
|
421
|
+
server = conn.servers.get(uuid)
|
422
|
+
if server then
|
423
|
+
server.destroy
|
424
|
+
else
|
425
|
+
puts "Server #{uuid} no longer exists."
|
426
|
+
end
|
306
427
|
rescue Exception => e
|
307
428
|
puts "Error deleting server: #{e.message}"
|
308
429
|
end
|
data/lib/kytoon/util.rb
CHANGED
@@ -116,6 +116,12 @@ REMOTE_EXEC_EOF
|
|
116
116
|
|
117
117
|
end
|
118
118
|
|
119
|
+
# Generate an ssh keypair using the specified base path
|
120
|
+
def self.generate_ssh_keypair(ssh_key_basepath)
|
121
|
+
FileUtils.mkdir_p(File.dirname(ssh_key_basepath))
|
122
|
+
%x{ssh-keygen -N '' -f #{ssh_key_basepath} -t rsa -q}
|
123
|
+
end
|
124
|
+
|
119
125
|
end
|
120
126
|
|
121
127
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kytoon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rdoc
|
@@ -172,7 +172,7 @@ dependencies:
|
|
172
172
|
- !ruby/object:Gem::Version
|
173
173
|
version: '0'
|
174
174
|
- !ruby/object:Gem::Dependency
|
175
|
-
name:
|
175
|
+
name: fog
|
176
176
|
requirement: !ruby/object:Gem::Requirement
|
177
177
|
none: false
|
178
178
|
requirements:
|
@@ -289,7 +289,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
289
289
|
version: '0'
|
290
290
|
segments:
|
291
291
|
- 0
|
292
|
-
hash:
|
292
|
+
hash: 3174001929267576694
|
293
293
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
294
294
|
none: false
|
295
295
|
requirements:
|