fog-libvirt-csem 0.9.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.
- checksums.yaml +7 -0
- data/CONTRIBUTORS.md +24 -0
- data/Gemfile +9 -0
- data/LICENSE.md +20 -0
- data/README.md +83 -0
- data/Rakefile +127 -0
- data/fog-libvirt-csem.gemspec +49 -0
- data/lib/fog/bin/libvirt.rb +58 -0
- data/lib/fog/libvirt/compute.rb +140 -0
- data/lib/fog/libvirt/models/compute/README.md +92 -0
- data/lib/fog/libvirt/models/compute/interface.rb +25 -0
- data/lib/fog/libvirt/models/compute/interfaces.rb +20 -0
- data/lib/fog/libvirt/models/compute/network.rb +33 -0
- data/lib/fog/libvirt/models/compute/networks.rb +20 -0
- data/lib/fog/libvirt/models/compute/nic.rb +50 -0
- data/lib/fog/libvirt/models/compute/nics.rb +12 -0
- data/lib/fog/libvirt/models/compute/node.rb +29 -0
- data/lib/fog/libvirt/models/compute/nodes.rb +20 -0
- data/lib/fog/libvirt/models/compute/pool.rb +84 -0
- data/lib/fog/libvirt/models/compute/pools.rb +20 -0
- data/lib/fog/libvirt/models/compute/server.rb +514 -0
- data/lib/fog/libvirt/models/compute/servers.rb +21 -0
- data/lib/fog/libvirt/models/compute/templates/network.xml.erb +6 -0
- data/lib/fog/libvirt/models/compute/templates/pool.xml.erb +6 -0
- data/lib/fog/libvirt/models/compute/templates/server.xml.erb +155 -0
- data/lib/fog/libvirt/models/compute/templates/volume.xml.erb +30 -0
- data/lib/fog/libvirt/models/compute/util/uri.rb +138 -0
- data/lib/fog/libvirt/models/compute/util/util.rb +32 -0
- data/lib/fog/libvirt/models/compute/volume.rb +129 -0
- data/lib/fog/libvirt/models/compute/volumes.rb +20 -0
- data/lib/fog/libvirt/requests/compute/clone_volume.rb +18 -0
- data/lib/fog/libvirt/requests/compute/create_domain.rb +17 -0
- data/lib/fog/libvirt/requests/compute/create_volume.rb +16 -0
- data/lib/fog/libvirt/requests/compute/define_domain.rb +17 -0
- data/lib/fog/libvirt/requests/compute/define_pool.rb +16 -0
- data/lib/fog/libvirt/requests/compute/destroy_interface.rb +18 -0
- data/lib/fog/libvirt/requests/compute/destroy_network.rb +17 -0
- data/lib/fog/libvirt/requests/compute/dhcp_leases.rb +37 -0
- data/lib/fog/libvirt/requests/compute/get_node_info.rb +37 -0
- data/lib/fog/libvirt/requests/compute/libversion.rb +18 -0
- data/lib/fog/libvirt/requests/compute/list_domains.rb +128 -0
- data/lib/fog/libvirt/requests/compute/list_interfaces.rb +57 -0
- data/lib/fog/libvirt/requests/compute/list_networks.rb +63 -0
- data/lib/fog/libvirt/requests/compute/list_pool_volumes.rb +19 -0
- data/lib/fog/libvirt/requests/compute/list_pools.rb +71 -0
- data/lib/fog/libvirt/requests/compute/list_volumes.rb +106 -0
- data/lib/fog/libvirt/requests/compute/mock_files/domain.xml +40 -0
- data/lib/fog/libvirt/requests/compute/pool_action.rb +19 -0
- data/lib/fog/libvirt/requests/compute/update_autostart.rb +18 -0
- data/lib/fog/libvirt/requests/compute/update_display.rb +36 -0
- data/lib/fog/libvirt/requests/compute/upload_volume.rb +31 -0
- data/lib/fog/libvirt/requests/compute/vm_action.rb +19 -0
- data/lib/fog/libvirt/requests/compute/volume_action.rb +18 -0
- data/lib/fog/libvirt/version.rb +5 -0
- data/lib/fog/libvirt.rb +16 -0
- data/minitests/server/server_test.rb +64 -0
- data/minitests/server/user_data_iso_test.rb +77 -0
- data/minitests/test_helper.rb +18 -0
- data/tests/helper.rb +17 -0
- data/tests/helpers/formats_helper.rb +100 -0
- data/tests/helpers/formats_helper_tests.rb +107 -0
- data/tests/helpers/mock_helper.rb +14 -0
- data/tests/helpers/succeeds_helper.rb +9 -0
- data/tests/libvirt/compute_tests.rb +19 -0
- data/tests/libvirt/models/compute/interface_tests.rb +27 -0
- data/tests/libvirt/models/compute/interfaces_tests.rb +14 -0
- data/tests/libvirt/models/compute/network_tests.rb +31 -0
- data/tests/libvirt/models/compute/networks_tests.rb +13 -0
- data/tests/libvirt/models/compute/nic_tests.rb +31 -0
- data/tests/libvirt/models/compute/nics_tests.rb +10 -0
- data/tests/libvirt/models/compute/pool_tests.rb +27 -0
- data/tests/libvirt/models/compute/pools_tests.rb +13 -0
- data/tests/libvirt/models/compute/server_tests.rb +63 -0
- data/tests/libvirt/models/compute/servers_tests.rb +14 -0
- data/tests/libvirt/models/compute/volume_tests.rb +38 -0
- data/tests/libvirt/models/compute/volumes_tests.rb +15 -0
- data/tests/libvirt/requests/compute/create_domain_tests.rb +21 -0
- data/tests/libvirt/requests/compute/define_domain_tests.rb +11 -0
- data/tests/libvirt/requests/compute/dhcp_leases_tests.rb +15 -0
- data/tests/libvirt/requests/compute/update_autostart_tests.rb +12 -0
- data/tests/libvirt/requests/compute/update_display.rb +13 -0
- metadata +335 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
require 'fog/compute/models/server'
|
|
2
|
+
require 'fog/libvirt/models/compute/util/util'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Fog
|
|
6
|
+
module Libvirt
|
|
7
|
+
class Compute
|
|
8
|
+
class Server < Fog::Compute::Server
|
|
9
|
+
include Fog::Libvirt::Util
|
|
10
|
+
attr_reader :xml
|
|
11
|
+
|
|
12
|
+
identity :id, :aliases => 'uuid'
|
|
13
|
+
|
|
14
|
+
attribute :cpus
|
|
15
|
+
attribute :cputime
|
|
16
|
+
attribute :os_type
|
|
17
|
+
attribute :memory_size
|
|
18
|
+
attribute :max_memory_size
|
|
19
|
+
attribute :name
|
|
20
|
+
attribute :arch
|
|
21
|
+
attribute :persistent
|
|
22
|
+
attribute :domain_type
|
|
23
|
+
attribute :uuid
|
|
24
|
+
attribute :autostart
|
|
25
|
+
attribute :nics
|
|
26
|
+
attribute :volumes
|
|
27
|
+
attribute :active
|
|
28
|
+
attribute :boot_order
|
|
29
|
+
attribute :display
|
|
30
|
+
attribute :cpu
|
|
31
|
+
attribute :hugepages
|
|
32
|
+
attribute :guest_agent
|
|
33
|
+
attribute :virtio_rng
|
|
34
|
+
|
|
35
|
+
attribute :state
|
|
36
|
+
|
|
37
|
+
# The following attributes are only needed when creating a new vm
|
|
38
|
+
#TODO: Add depreciation warning
|
|
39
|
+
attr_accessor :iso_dir, :iso_file
|
|
40
|
+
attr_accessor :network_interface_type ,:network_nat_network, :network_bridge_name
|
|
41
|
+
attr_accessor :volume_format_type, :volume_allocation,:volume_capacity, :volume_name, :volume_pool_name, :volume_template_name, :volume_path
|
|
42
|
+
attr_accessor :password
|
|
43
|
+
attr_accessor :user_data
|
|
44
|
+
|
|
45
|
+
# Can be created by passing in :xml => "<xml to create domain/server>"
|
|
46
|
+
# or by providing :template_options => {
|
|
47
|
+
# :name => "", :cpus => 1, :memory_size => 256 , :volume_template
|
|
48
|
+
# }
|
|
49
|
+
|
|
50
|
+
def initialize(attributes={} )
|
|
51
|
+
@xml = attributes.delete(:xml)
|
|
52
|
+
verify_boot_order(attributes[:boot_order])
|
|
53
|
+
super defaults.merge(attributes)
|
|
54
|
+
initialize_nics
|
|
55
|
+
initialize_volumes
|
|
56
|
+
@user_data = attributes.delete(:user_data)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def new?
|
|
60
|
+
uuid.nil?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def save
|
|
64
|
+
raise Fog::Errors::Error.new('Saving an existing server may create a duplicate') unless new?
|
|
65
|
+
create_or_clone_volume unless xml or @volumes
|
|
66
|
+
create_user_data_iso if user_data
|
|
67
|
+
@xml ||= to_xml
|
|
68
|
+
self.id = (persistent ? service.define_domain(xml) : service.create_domain(xml)).uuid
|
|
69
|
+
reload
|
|
70
|
+
rescue => e
|
|
71
|
+
raise Fog::Errors::Error.new("Error saving the server: #{e}")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def start
|
|
75
|
+
return true if active?
|
|
76
|
+
action_status = service.vm_action(uuid, :create)
|
|
77
|
+
reload
|
|
78
|
+
action_status
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def update_autostart(value)
|
|
82
|
+
service.update_autostart(uuid, value)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def mac
|
|
86
|
+
nics.first.mac if nics && nics.first
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def disk_path
|
|
90
|
+
volumes.first.path if volumes and volumes.first
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def destroy(options={ :destroy_volumes => false})
|
|
94
|
+
poweroff unless stopped?
|
|
95
|
+
service.vm_action(uuid, :undefine, 4) # Remove NVRAM if exists
|
|
96
|
+
volumes.each { |vol| vol.destroy } if options[:destroy_volumes]
|
|
97
|
+
true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def reboot
|
|
101
|
+
action_status = service.vm_action(uuid, :reboot)
|
|
102
|
+
reload
|
|
103
|
+
action_status
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def poweroff
|
|
107
|
+
action_status = service.vm_action(uuid, :destroy)
|
|
108
|
+
reload
|
|
109
|
+
action_status
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def shutdown
|
|
113
|
+
action_status = service.vm_action(uuid, :shutdown)
|
|
114
|
+
reload
|
|
115
|
+
action_status
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def resume
|
|
119
|
+
action_status = service.vm_action(uuid, :resume)
|
|
120
|
+
reload
|
|
121
|
+
action_status
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def suspend
|
|
125
|
+
action_status = service.vm_action(uuid, :suspend)
|
|
126
|
+
reload
|
|
127
|
+
action_status
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def stopped?
|
|
131
|
+
state == "shutoff"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def ready?
|
|
135
|
+
state == "running"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
#alias methods
|
|
139
|
+
alias_method :halt, :poweroff
|
|
140
|
+
alias_method :stop, :shutdown
|
|
141
|
+
alias_method :active?, :active
|
|
142
|
+
alias_method :autostart?, :autostart
|
|
143
|
+
|
|
144
|
+
def volumes
|
|
145
|
+
# lazy loading of volumes
|
|
146
|
+
@volumes ||= (@volumes_path || []).map{|path| service.volumes.all(:path => path).first }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def private_ip_address
|
|
150
|
+
ip_address(:private)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def public_ip_address
|
|
154
|
+
ip_address(:public)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def ssh(commands)
|
|
158
|
+
requires :ssh_ip_address, :username
|
|
159
|
+
|
|
160
|
+
ssh_options={}
|
|
161
|
+
ssh_options[:password] = password unless password.nil?
|
|
162
|
+
ssh_options[:proxy]= ssh_proxy unless ssh_proxy.nil?
|
|
163
|
+
|
|
164
|
+
super(commands, ssh_options)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def ssh_proxy
|
|
168
|
+
begin
|
|
169
|
+
require 'net/ssh/proxy/command'
|
|
170
|
+
rescue LoadError
|
|
171
|
+
Fog::Logger.warning("'net/ssh' missing, please install and try again.")
|
|
172
|
+
exit(1)
|
|
173
|
+
end
|
|
174
|
+
# if this is a direct connection, we don't need a proxy to be set.
|
|
175
|
+
return nil unless connection.uri.ssh_enabled?
|
|
176
|
+
user_string= service.uri.user ? "-l #{service.uri.user}" : ""
|
|
177
|
+
Net::SSH::Proxy::Command.new("ssh #{user_string} #{service.uri.host} nc %h %p")
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Transfers a file
|
|
181
|
+
def scp(local_path, remote_path, upload_options = {})
|
|
182
|
+
requires :ssh_ip_address, :username
|
|
183
|
+
|
|
184
|
+
scp_options = {}
|
|
185
|
+
scp_options[:password] = password unless self.password.nil?
|
|
186
|
+
scp_options[:key_data] = [private_key] if self.private_key
|
|
187
|
+
scp_options[:proxy]= ssh_proxy unless self.ssh_proxy.nil?
|
|
188
|
+
|
|
189
|
+
Fog::SCP.new(ssh_ip_address, username, scp_options).upload(local_path, remote_path, upload_options)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Sets up a new key
|
|
193
|
+
def setup(credentials = {})
|
|
194
|
+
requires :public_key, :ssh_ip_address, :username
|
|
195
|
+
|
|
196
|
+
credentials[:proxy]= ssh_proxy unless ssh_proxy.nil?
|
|
197
|
+
credentials[:password] = password unless self.password.nil?
|
|
198
|
+
credentials[:key_data] = [private_key] if self.private_key
|
|
199
|
+
|
|
200
|
+
commands = [
|
|
201
|
+
%{mkdir .ssh},
|
|
202
|
+
# %{passwd -l #{username}}, #Not sure if we need this here
|
|
203
|
+
# %{echo "#{Fog::JSON.encode(attributes)}" >> ~/attributes.json}
|
|
204
|
+
]
|
|
205
|
+
if public_key
|
|
206
|
+
commands << %{echo "#{public_key}" >> ~/.ssh/authorized_keys}
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# wait for domain to be ready
|
|
210
|
+
Timeout::timeout(360) do
|
|
211
|
+
begin
|
|
212
|
+
Timeout::timeout(8) do
|
|
213
|
+
Fog::SSH.new(ssh_ip_address, username, credentials.merge(:timeout => 4)).run('pwd')
|
|
214
|
+
end
|
|
215
|
+
rescue Errno::ECONNREFUSED
|
|
216
|
+
sleep(2)
|
|
217
|
+
retry
|
|
218
|
+
rescue Net::SSH::AuthenticationFailed, Timeout::Error
|
|
219
|
+
retry
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
Fog::SSH.new(ssh_ip_address, username, credentials).run(commands)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def update_display attrs = {}
|
|
226
|
+
service.update_display attrs.merge(:uuid => uuid)
|
|
227
|
+
reload
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# can't use deprecate method, as the value is part of the display hash
|
|
231
|
+
def vnc_port
|
|
232
|
+
Fog::Logger.deprecation("#{self.class} => #vnc_port is deprecated, use #display[:port] instead [light_black](#{caller.first})[/]")
|
|
233
|
+
display[:port]
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def generate_config_iso(user_data, &blk)
|
|
237
|
+
Dir.mktmpdir('config') do |wd|
|
|
238
|
+
generate_config_iso_in_dir(wd, user_data, &blk)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def generate_config_iso_in_dir(dir_path, user_data, &blk)
|
|
243
|
+
FileUtils.touch(File.join(dir_path, "meta-data"))
|
|
244
|
+
File.open(File.join(dir_path, 'user-data'), 'w') { |f| f.write user_data }
|
|
245
|
+
|
|
246
|
+
isofile = Tempfile.new(['init', '.iso']).path
|
|
247
|
+
unless system("genisoimage -output #{isofile} -volid cidata -joliet -rock #{File.join(dir_path, 'user-data')} #{File.join(dir_path, 'meta-data')}")
|
|
248
|
+
raise Fog::Errors::Error.new("Couldn't generate cloud-init iso disk with genisoimage.")
|
|
249
|
+
end
|
|
250
|
+
blk.call(isofile)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def create_user_data_iso
|
|
254
|
+
generate_config_iso(user_data) do |iso|
|
|
255
|
+
vol = service.volumes.create(:name => cloud_init_volume_name, :capacity => "#{File.size(iso)}b", :allocation => "0G")
|
|
256
|
+
vol.upload_image(iso)
|
|
257
|
+
@iso_file = cloud_init_volume_name
|
|
258
|
+
@iso_dir = File.dirname(vol.path) if vol.path
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def cloud_init_volume_name
|
|
263
|
+
"#{name}-cloud-init.iso"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
private
|
|
267
|
+
attr_accessor :volumes_path
|
|
268
|
+
|
|
269
|
+
# This tests the library version before redefining the address
|
|
270
|
+
# method for this instance to use a method compatible with
|
|
271
|
+
# earlier libvirt libraries, or uses the dhcp method from more
|
|
272
|
+
# recent releases.
|
|
273
|
+
def addresses(service_arg=service, options={})
|
|
274
|
+
addresses_method = self.method(:addresses_dhcp)
|
|
275
|
+
# check if ruby-libvirt was compiled against a new enough version
|
|
276
|
+
# that can use dhcp_leases, as otherwise it will not provide the
|
|
277
|
+
# method dhcp_leases on any of the network objects.
|
|
278
|
+
has_dhcp_leases = true
|
|
279
|
+
begin
|
|
280
|
+
service.networks.first.dhcp_leases(self.mac)
|
|
281
|
+
rescue NoMethodError
|
|
282
|
+
has_dhcp_leases = false
|
|
283
|
+
rescue
|
|
284
|
+
# assume some other odd exception.
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# if ruby-libvirt not compiled with support, or remote library is
|
|
288
|
+
# too old (must be newer than 1.2.8), then use old fallback
|
|
289
|
+
if not has_dhcp_leases or service.libversion() < 1002008
|
|
290
|
+
addresses_method = self.method(:addresses_ip_command)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# replace current definition for this instance with correct one for
|
|
294
|
+
# detected libvirt to perform check once for connection
|
|
295
|
+
(class << self; self; end).class_eval do
|
|
296
|
+
define_method(:addresses, addresses_method)
|
|
297
|
+
end
|
|
298
|
+
addresses(service_arg, options)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def ssh_ip_command(ip_command, uri)
|
|
302
|
+
# Retrieve the parts we need from the service to setup our ssh options
|
|
303
|
+
user=uri.user #could be nil
|
|
304
|
+
host=uri.host
|
|
305
|
+
keyfile=uri.keyfile
|
|
306
|
+
port=uri.port
|
|
307
|
+
|
|
308
|
+
# Setup the options
|
|
309
|
+
ssh_options={}
|
|
310
|
+
ssh_options[:keys]=[ keyfile ] unless keyfile.nil?
|
|
311
|
+
ssh_options[:port]=port unless keyfile.nil?
|
|
312
|
+
ssh_options[:paranoid]=true if uri.no_verify?
|
|
313
|
+
|
|
314
|
+
begin
|
|
315
|
+
result=Fog::SSH.new(host, user, ssh_options).run(ip_command)
|
|
316
|
+
rescue Errno::ECONNREFUSED
|
|
317
|
+
raise Fog::Errors::Error.new("Connection was refused to host #{host} to retrieve the ip_address for #{mac}")
|
|
318
|
+
rescue Net::SSH::AuthenticationFailed
|
|
319
|
+
raise Fog::Errors::Error.new("Error authenticating over ssh to host #{host} and user #{user}")
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Check for a clean exit code
|
|
323
|
+
if result.first.status == 0
|
|
324
|
+
return result.first.stdout.strip
|
|
325
|
+
else
|
|
326
|
+
# We got a failure executing the command
|
|
327
|
+
raise Fog::Errors::Error.new("The command #{ip_command} failed to execute with a clean exit code")
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def local_ip_command(ip_command)
|
|
332
|
+
# Execute the ip_command locally
|
|
333
|
+
# Initialize empty ip_address string
|
|
334
|
+
ip_address=""
|
|
335
|
+
|
|
336
|
+
IO.popen("#{ip_command}") do |p|
|
|
337
|
+
p.each_line do |l|
|
|
338
|
+
ip_address+=l
|
|
339
|
+
end
|
|
340
|
+
status=Process.waitpid2(p.pid)[1].exitstatus
|
|
341
|
+
if status!=0
|
|
342
|
+
raise Fog::Errors::Error.new("The command #{ip_command} failed to execute with a clean exit code")
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
#Strip any new lines from the string
|
|
347
|
+
ip_address.chomp
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Locale-friendly removal of non-alpha nums
|
|
351
|
+
DOMAIN_CLEANUP_REGEXP = Regexp.compile('[\W_-]')
|
|
352
|
+
|
|
353
|
+
# This retrieves the ip address of the mac address using ip_command
|
|
354
|
+
# It returns an array of public and private ip addresses
|
|
355
|
+
# Currently only one ip address is returned, but in the future this could be multiple
|
|
356
|
+
# if the server has multiple network interface
|
|
357
|
+
def addresses_ip_command(service_arg=service, options={})
|
|
358
|
+
mac=self.mac
|
|
359
|
+
|
|
360
|
+
# Aug 24 17:34:41 juno arpwatch: new station 10.247.4.137 52:54:00:88:5a:0a eth0.4
|
|
361
|
+
# Aug 24 17:37:19 juno arpwatch: changed ethernet address 10.247.4.137 52:54:00:27:33:00 (52:54:00:88:5a:0a) eth0.4
|
|
362
|
+
# Check if another ip_command string was provided
|
|
363
|
+
ip_command_global=service_arg.ip_command.nil? ? 'grep $mac /var/log/arpwatch.log|sed -e "s/new station//"|sed -e "s/changed ethernet address//g" |sed -e "s/reused old ethernet //" |tail -1 |cut -d ":" -f 4-| cut -d " " -f 3' : service_arg.ip_command
|
|
364
|
+
ip_command_local=options[:ip_command].nil? ? ip_command_global : options[:ip_command]
|
|
365
|
+
|
|
366
|
+
ip_command="mac=#{mac}; server_name=#{name.gsub(DOMAIN_CLEANUP_REGEXP, '_')}; "+ip_command_local
|
|
367
|
+
|
|
368
|
+
ip_address=nil
|
|
369
|
+
|
|
370
|
+
if service_arg.uri.ssh_enabled?
|
|
371
|
+
ip_address=ssh_ip_command(ip_command, service_arg.uri)
|
|
372
|
+
else
|
|
373
|
+
# It's not ssh enabled, so we assume it is
|
|
374
|
+
if service_arg.uri.transport=="tls"
|
|
375
|
+
raise Fog::Errors::Error.new("TlS remote transport is not currently supported, only ssh")
|
|
376
|
+
end
|
|
377
|
+
ip_address=local_ip_command(ip_command)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# The Ip-address command has been run either local or remote now
|
|
381
|
+
|
|
382
|
+
if ip_address==""
|
|
383
|
+
#The grep didn't find an ip address result"
|
|
384
|
+
ip_address=nil
|
|
385
|
+
else
|
|
386
|
+
# To be sure that the command didn't return another random string
|
|
387
|
+
# We check if the result is an actual ip-address
|
|
388
|
+
# otherwise we return nil
|
|
389
|
+
unless ip_address=~/^(\d{1,3}\.){3}\d{1,3}$/
|
|
390
|
+
raise Fog::Errors::Error.new(
|
|
391
|
+
"The result of #{ip_command} does not have valid ip-address format\n"+
|
|
392
|
+
"Result was: #{ip_address}\n"
|
|
393
|
+
)
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
return { :public => [ip_address], :private => [ip_address]}
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# This retrieves the ip address of the mac address using dhcp_leases
|
|
401
|
+
# It returns an array of public and private ip addresses
|
|
402
|
+
# Currently only one ip address is returned, but in the future this could be multiple
|
|
403
|
+
# if the server has multiple network interface
|
|
404
|
+
def addresses_dhcp(service_arg=service, options={})
|
|
405
|
+
mac=self.mac
|
|
406
|
+
|
|
407
|
+
ip_address = nil
|
|
408
|
+
nic = self.nics.find {|nic| nic.mac==mac}
|
|
409
|
+
if !nic.nil?
|
|
410
|
+
service.networks.all.each do |net|
|
|
411
|
+
if net.name == nic.network
|
|
412
|
+
leases = net.dhcp_leases(mac, 0)
|
|
413
|
+
# Assume the lease expiring last is the current IP address
|
|
414
|
+
ip_address = leases.sort_by { |lse| lse["expirytime"] }.last["ipaddr"] if !leases.empty?
|
|
415
|
+
break
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
return { :public => [ip_address], :private => [ip_address] }
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def ip_address(key)
|
|
424
|
+
addresses[key].nil? ? nil : addresses[key].first
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def initialize_nics
|
|
428
|
+
if nics
|
|
429
|
+
nics.map! { |nic| nic.is_a?(Hash) ? service.nics.new(nic) : nic }
|
|
430
|
+
else
|
|
431
|
+
self.nics = [service.nics.new({:type => network_interface_type, :bridge => network_bridge_name, :network => network_nat_network})]
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def initialize_volumes
|
|
436
|
+
if attributes[:volumes] && !attributes[:volumes].empty?
|
|
437
|
+
@volumes = attributes[:volumes].map { |vol| vol.is_a?(Hash) ? service.volumes.new(vol) : vol }
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def create_or_clone_volume
|
|
442
|
+
options = {:name => volume_name || default_volume_name}
|
|
443
|
+
# Check if a disk template was specified
|
|
444
|
+
if volume_template_name
|
|
445
|
+
template_volume = service.volumes.all(:name => volume_template_name).first
|
|
446
|
+
raise Fog::Errors::Error.new("Template #{volume_template_name} not found") unless template_volume
|
|
447
|
+
begin
|
|
448
|
+
volume = template_volume.clone("#{options[:name]}")
|
|
449
|
+
rescue => e
|
|
450
|
+
raise Fog::Errors::Error.new("Error creating the volume : #{e}")
|
|
451
|
+
end
|
|
452
|
+
else
|
|
453
|
+
# If no template volume was given, let's create our own volume
|
|
454
|
+
options[:pool_name] = volume_pool_name if volume_pool_name
|
|
455
|
+
options[:format_type] = volume_format_type if volume_format_type
|
|
456
|
+
options[:capacity] = volume_capacity if volume_capacity
|
|
457
|
+
options[:allocation] = volume_allocation if volume_allocation
|
|
458
|
+
|
|
459
|
+
begin
|
|
460
|
+
volume = service.volumes.create(options)
|
|
461
|
+
rescue => e
|
|
462
|
+
raise Fog::Errors::Error.new("Error creating the volume : #{e}")
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
@volumes.nil? ? @volumes = [volume] : @volumes << volume
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
def default_iso_dir
|
|
469
|
+
"/var/lib/libvirt/images"
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
def default_volume_name
|
|
473
|
+
"#{name}.#{volume_format_type || 'img'}"
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
def defaults
|
|
477
|
+
{
|
|
478
|
+
:persistent => true,
|
|
479
|
+
:cpus => 1,
|
|
480
|
+
:memory_size => 256 *1024,
|
|
481
|
+
:name => randomized_name,
|
|
482
|
+
:os_type => "hvm",
|
|
483
|
+
:arch => "x86_64",
|
|
484
|
+
:domain_type => "kvm",
|
|
485
|
+
:autostart => false,
|
|
486
|
+
:iso_dir => default_iso_dir,
|
|
487
|
+
:network_interface_type => "network",
|
|
488
|
+
:network_nat_network => "default",
|
|
489
|
+
:network_bridge_name => "br0",
|
|
490
|
+
:boot_order => %w[hd cdrom network],
|
|
491
|
+
:display => default_display,
|
|
492
|
+
:cpu => {},
|
|
493
|
+
:hugepages => false,
|
|
494
|
+
:guest_agent => true,
|
|
495
|
+
:virtio_rng => {},
|
|
496
|
+
}
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def verify_boot_order order = []
|
|
500
|
+
valid_boot_media = %w[cdrom fd hd network]
|
|
501
|
+
if order
|
|
502
|
+
order.each do |b|
|
|
503
|
+
raise "invalid boot order, possible values are any combination of: #{valid_boot_media.join(', ')}" unless valid_boot_media.include?(b)
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def default_display
|
|
509
|
+
{:port => '-1', :listen => '127.0.0.1', :type => 'vnc', :password => '' }
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'fog/core/collection'
|
|
2
|
+
require 'fog/libvirt/models/compute/server'
|
|
3
|
+
|
|
4
|
+
module Fog
|
|
5
|
+
module Libvirt
|
|
6
|
+
class Compute
|
|
7
|
+
class Servers < Fog::Collection
|
|
8
|
+
model Fog::Libvirt::Compute::Server
|
|
9
|
+
|
|
10
|
+
def all(filter={})
|
|
11
|
+
load(service.list_domains(filter))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get(uuid)
|
|
15
|
+
data = service.list_domains(:uuid => uuid)
|
|
16
|
+
new data.first if data
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|