ovirt 0.1.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 +15 -0
- data/.rspec +3 -0
- data/LICENSE.txt +13 -0
- data/README.md +35 -0
- data/lib/ovirt/api.rb +31 -0
- data/lib/ovirt/cdrom.rb +12 -0
- data/lib/ovirt/cluster.rb +27 -0
- data/lib/ovirt/data_center.rb +24 -0
- data/lib/ovirt/disk.rb +30 -0
- data/lib/ovirt/domain.rb +12 -0
- data/lib/ovirt/event.rb +492 -0
- data/lib/ovirt/event_monitor.rb +36 -0
- data/lib/ovirt/exception.rb +13 -0
- data/lib/ovirt/file.rb +13 -0
- data/lib/ovirt/group.rb +12 -0
- data/lib/ovirt/host.rb +44 -0
- data/lib/ovirt/host_nic.rb +38 -0
- data/lib/ovirt/inventory.rb +177 -0
- data/lib/ovirt/network.rb +16 -0
- data/lib/ovirt/nic.rb +31 -0
- data/lib/ovirt/object.rb +315 -0
- data/lib/ovirt/permission.rb +20 -0
- data/lib/ovirt/permit.rb +14 -0
- data/lib/ovirt/role.rb +13 -0
- data/lib/ovirt/service.rb +332 -0
- data/lib/ovirt/snapshot.rb +28 -0
- data/lib/ovirt/statistic.rb +37 -0
- data/lib/ovirt/storage.rb +14 -0
- data/lib/ovirt/storage_domain.rb +48 -0
- data/lib/ovirt/tag.rb +23 -0
- data/lib/ovirt/template.rb +185 -0
- data/lib/ovirt/user.rb +15 -0
- data/lib/ovirt/version.rb +3 -0
- data/lib/ovirt/vm.rb +327 -0
- data/lib/ovirt/vmpool.rb +14 -0
- data/lib/ovirt.rb +35 -0
- data/spec/event_spec.rb +26 -0
- data/spec/object_spec.rb +12 -0
- data/spec/service_spec.rb +30 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/template_spec.rb +141 -0
- data/spec/vm_spec.rb +189 -0
- metadata +224 -0
data/lib/ovirt/vm.rb
ADDED
@@ -0,0 +1,327 @@
|
|
1
|
+
module Ovirt
|
2
|
+
class Vm < Template
|
3
|
+
|
4
|
+
self.top_level_strings = [:name, :origin, :type, :description]
|
5
|
+
self.top_level_booleans = [:stateless]
|
6
|
+
self.top_level_integers = [:memory]
|
7
|
+
self.top_level_timestamps = [:creation_time, :start_time]
|
8
|
+
self.top_level_objects = [:cluster, :template, :host]
|
9
|
+
|
10
|
+
attr_accessor :creation_status_link
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
|
15
|
+
@creation_status_link = @relationships.delete(:creation_status)
|
16
|
+
end
|
17
|
+
|
18
|
+
def creation_status
|
19
|
+
return nil if @creation_status_link.blank?
|
20
|
+
@service.status(@creation_status_link)
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
if block_given?
|
25
|
+
operation(:start) { |xml| yield xml }
|
26
|
+
else
|
27
|
+
operation(:start)
|
28
|
+
end
|
29
|
+
rescue Ovirt::Error => err
|
30
|
+
raise VmAlreadyRunning, err.message if err.message.include?("VM is running.")
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop
|
35
|
+
operation(:stop)
|
36
|
+
rescue Ovirt::Error => err
|
37
|
+
raise VmIsNotRunning, err.message if err.message.include?("VM is not running")
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
|
41
|
+
def shutdown
|
42
|
+
operation(:shutdown)
|
43
|
+
rescue Ovirt::Error => err
|
44
|
+
raise VmIsNotRunning, err.message if err.message.include?("VM is not running")
|
45
|
+
raise
|
46
|
+
end
|
47
|
+
|
48
|
+
def destroy
|
49
|
+
# TODO:
|
50
|
+
# 1. If VM was running, wait for it to stop
|
51
|
+
begin
|
52
|
+
stop
|
53
|
+
rescue VmIsNotRunning
|
54
|
+
end
|
55
|
+
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
def move(storage_domain)
|
60
|
+
response = operation(:move) do |xml|
|
61
|
+
xml.storage_domain(:id => self.class.object_to_id(storage_domain))
|
62
|
+
end
|
63
|
+
|
64
|
+
# Sample Response
|
65
|
+
# <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
66
|
+
# <action id="13be9571-61a0-40ef-be6c-50696f61cab1" href="/api/vms/5819ddca-47c0-47d8-8b75-c5b8d1f2b354/move/13be9571-61a0-40ef-be6c-50696f61cab1">
|
67
|
+
# <link rel="parent" href="/api/vms/5819ddca-47c0-47d8-8b75-c5b8d1f2b354"/>
|
68
|
+
# <link rel="replay" href="/api/vms/5819ddca-47c0-47d8-8b75-c5b8d1f2b354/move"/>
|
69
|
+
# <async>true</async>
|
70
|
+
# <storage_domain id="08d61895-b465-406f-955c-72fd9ddbbe05"/>
|
71
|
+
# <status>
|
72
|
+
# <state>pending</state>
|
73
|
+
# </status>
|
74
|
+
# </action>
|
75
|
+
doc = Nokogiri::XML(response)
|
76
|
+
action = doc.xpath("//action").first
|
77
|
+
raise Ovirt::Error, "No Action in Response: #{response.inspect}" if action.nil?
|
78
|
+
action['href']
|
79
|
+
end
|
80
|
+
|
81
|
+
# cpu_hash needs to look like { :cores => 1, :sockets => 1 }
|
82
|
+
def cpu_topology=(cpu_hash)
|
83
|
+
update! do |xml|
|
84
|
+
xml.cpu do
|
85
|
+
xml.topology(cpu_hash)
|
86
|
+
end
|
87
|
+
xml.memory self[:memory] # HACK: RHEVM BUG: RHEVM resets it to 10GB, unless we set it
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def description=(value)
|
92
|
+
update! do |xml|
|
93
|
+
xml.description value.to_s
|
94
|
+
xml.memory self[:memory] # HACK: RHEVM BUG: RHEVM resets it to 10GB, unless we set it
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def host_affinity=(host, affinity = :migratable)
|
99
|
+
update! do |xml|
|
100
|
+
xml.memory self[:memory] # HACK: RHEVM BUG: RHEVM resets it to 10GB, unless we set it
|
101
|
+
xml.placement_policy do
|
102
|
+
if host.nil?
|
103
|
+
xml.host
|
104
|
+
else
|
105
|
+
xml.host(:id => self.class.object_to_id(host))
|
106
|
+
end
|
107
|
+
xml.affinity affinity.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def memory=(value)
|
113
|
+
update! do |xml|
|
114
|
+
xml.memory value
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def memory_reserve=(value)
|
119
|
+
update! do |xml|
|
120
|
+
xml.memory_policy do
|
121
|
+
xml.guaranteed(value)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Attaches a payload.
|
127
|
+
#
|
128
|
+
# payloads:: Hash of payload_type => {file_name => content} that will be
|
129
|
+
# attached. Acceptable payload_types are floppy or cdrom.
|
130
|
+
def attach_payload(payloads)
|
131
|
+
send("attach_payload_#{payload_version}".to_sym, payloads)
|
132
|
+
end
|
133
|
+
|
134
|
+
def payload_version
|
135
|
+
version = service.version
|
136
|
+
|
137
|
+
if version[:major].to_i >= 3
|
138
|
+
return "3_0" if version[:minor].to_i < 3
|
139
|
+
return "3_3"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def attach_payload_3_0(payloads)
|
144
|
+
update! do |xml|
|
145
|
+
xml.payloads do
|
146
|
+
payloads.each do |type, files|
|
147
|
+
xml.payload(:type => type) do
|
148
|
+
files.each do |file_name, content|
|
149
|
+
xml.file(:name => file_name) do
|
150
|
+
xml.content content
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def attach_payload_3_3(payloads)
|
160
|
+
update! do |xml|
|
161
|
+
xml.payloads do
|
162
|
+
payloads.each do |type, files|
|
163
|
+
xml.payload(:type => type) do
|
164
|
+
xml.files do
|
165
|
+
files.each do |file_name, content|
|
166
|
+
xml.file do
|
167
|
+
xml.name file_name
|
168
|
+
xml.content content
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Detaches a payload
|
179
|
+
#
|
180
|
+
# types:: A payload type or Array of payload types to detach.
|
181
|
+
# Acceptable types are floppy or cdrom.
|
182
|
+
def detach_payload(types)
|
183
|
+
# HACK: The removal of payloads is not supported until possibly RHEVM 3.1.1
|
184
|
+
# https://bugzilla.redhat.com/show_bug.cgi?id=882649
|
185
|
+
# For now, just set the payload to blank content.
|
186
|
+
payload = Array(types).each_with_object({}) { |t, h| h[t] = {} }
|
187
|
+
attach_payload(payload)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Attaches the +files+ as a floppy drive payload.
|
191
|
+
#
|
192
|
+
# files:: Hash of file_name => content that will be attached as a floppy
|
193
|
+
def attach_floppy(files)
|
194
|
+
attach_payload("floppy" => files || {})
|
195
|
+
end
|
196
|
+
|
197
|
+
# Detaches the floppy drive payload.
|
198
|
+
def detach_floppy
|
199
|
+
detach_payload("floppy")
|
200
|
+
end
|
201
|
+
|
202
|
+
def boot_from_network
|
203
|
+
start do |xml|
|
204
|
+
xml.vm do
|
205
|
+
xml.os do
|
206
|
+
xml.boot(:dev => 'network')
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
rescue Ovirt::Error => err
|
211
|
+
raise unless err.message =~ /disks .+ are locked/
|
212
|
+
raise VmNotReadyToBoot.new [err.message, err]
|
213
|
+
end
|
214
|
+
|
215
|
+
def boot_from_cdrom(iso_file_name)
|
216
|
+
start do |xml|
|
217
|
+
xml.vm do
|
218
|
+
xml.os do
|
219
|
+
xml.boot(:dev => 'cdrom')
|
220
|
+
end
|
221
|
+
xml.cdroms do
|
222
|
+
xml.cdrom do
|
223
|
+
xml.file(:id => iso_file_name)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
rescue Ovirt::Error => err
|
229
|
+
raise unless err.message =~ /disks .+ are locked/
|
230
|
+
raise VmNotReadyToBoot.new [err.message, err]
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.parse_xml(xml)
|
234
|
+
hash = super
|
235
|
+
node = xml_to_nokogiri(xml)
|
236
|
+
|
237
|
+
parse_first_node(node, :placement_policy, hash,
|
238
|
+
:node => [:affinity])
|
239
|
+
|
240
|
+
parse_first_node_with_hash(node, 'placement_policy/host', hash[:placement_policy][:host] = {},
|
241
|
+
:attribute => [:id])
|
242
|
+
|
243
|
+
parse_first_node(node, :memory_policy, hash,
|
244
|
+
:node_to_i => [:guaranteed])
|
245
|
+
|
246
|
+
hash[:guest_info] = {}
|
247
|
+
node.xpath('guest_info').each do |gi|
|
248
|
+
ips = hash[:guest_info][:ips] = []
|
249
|
+
gi.xpath('ips/ip').each do |ip|
|
250
|
+
ips << {:address => ip[:address]}
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
hash
|
255
|
+
end
|
256
|
+
|
257
|
+
def create_device(device_type)
|
258
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
259
|
+
xml.send(device_type) { yield xml if block_given? }
|
260
|
+
end
|
261
|
+
data = builder.doc.root.to_xml
|
262
|
+
path = "#{api_endpoint}/#{device_type.pluralize}"
|
263
|
+
|
264
|
+
@service.resource_post(path, data)
|
265
|
+
end
|
266
|
+
|
267
|
+
def create_nic(options = {})
|
268
|
+
create_device("nic") do |xml|
|
269
|
+
xml.name options[:name]
|
270
|
+
xml.interface options[:interface] unless options[:interface].blank?
|
271
|
+
xml.network(:id => options[:network_id]) unless options[:network_id].blank?
|
272
|
+
xml.mac(:address => options[:mac_address]) unless options[:mac_address].blank?
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def create_disk(options = {})
|
277
|
+
create_device("disk") do |xml|
|
278
|
+
[:name, :interface, :format, :size, :type].each do |key|
|
279
|
+
next if options[key].blank?
|
280
|
+
xml.send("#{key}_", options[key])
|
281
|
+
end
|
282
|
+
|
283
|
+
[:sparse, :bootable, :wipe_after_delete, :propagate_errors].each do |key|
|
284
|
+
xml.send("#{key}_", options[key]) unless options[key].nil?
|
285
|
+
end
|
286
|
+
|
287
|
+
xml.storage_domains { xml.storage_domain(:id => options[:storage]) } if options[:storage]
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def create_snapshot(desc)
|
292
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
293
|
+
xml.snapshot do
|
294
|
+
xml.description desc
|
295
|
+
end
|
296
|
+
end
|
297
|
+
data = builder.doc.root.to_xml
|
298
|
+
path = "#{api_endpoint}/snapshots"
|
299
|
+
|
300
|
+
response = @service.resource_post(path, data)
|
301
|
+
|
302
|
+
snap = Snapshot.create_from_xml(@service, response)
|
303
|
+
|
304
|
+
while snap[:snapshot_status] == "locked"
|
305
|
+
sleep 2
|
306
|
+
snap.reload
|
307
|
+
end
|
308
|
+
snap
|
309
|
+
end
|
310
|
+
|
311
|
+
def create_template(options={})
|
312
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
313
|
+
xml.template do
|
314
|
+
xml.name options[:name]
|
315
|
+
xml.vm(:id => self[:id])
|
316
|
+
end
|
317
|
+
end
|
318
|
+
data = builder.doc.root.to_xml
|
319
|
+
|
320
|
+
response = @service.resource_post(:templates, data)
|
321
|
+
Template.create_from_xml(@service, response)
|
322
|
+
rescue Ovirt::Error => err
|
323
|
+
raise TemplateAlreadyExists, err.message if err.message.include?("Template name already exists")
|
324
|
+
raise
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
data/lib/ovirt/vmpool.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Ovirt
|
2
|
+
class Vmpool < Object
|
3
|
+
|
4
|
+
self.top_level_strings = [:name, :description]
|
5
|
+
self.top_level_integers = [:size]
|
6
|
+
self.top_level_objects = [:cluster, :template]
|
7
|
+
|
8
|
+
def self.parse_xml(xml)
|
9
|
+
node, hash = xml_to_hash(xml)
|
10
|
+
|
11
|
+
hash
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/ovirt.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'more_core_extensions/all'
|
3
|
+
|
4
|
+
require 'ovirt/exception'
|
5
|
+
require 'ovirt/object'
|
6
|
+
require 'ovirt/version'
|
7
|
+
|
8
|
+
require 'ovirt/api'
|
9
|
+
require 'ovirt/cdrom'
|
10
|
+
require 'ovirt/cluster'
|
11
|
+
require 'ovirt/data_center'
|
12
|
+
require 'ovirt/disk'
|
13
|
+
require 'ovirt/domain'
|
14
|
+
require 'ovirt/event'
|
15
|
+
require 'ovirt/event_monitor'
|
16
|
+
require 'ovirt/file'
|
17
|
+
require 'ovirt/group'
|
18
|
+
require 'ovirt/host'
|
19
|
+
require 'ovirt/host_nic'
|
20
|
+
require 'ovirt/inventory'
|
21
|
+
require 'ovirt/network'
|
22
|
+
require 'ovirt/nic'
|
23
|
+
require 'ovirt/permission'
|
24
|
+
require 'ovirt/permit'
|
25
|
+
require 'ovirt/role'
|
26
|
+
require 'ovirt/service'
|
27
|
+
require 'ovirt/snapshot'
|
28
|
+
require 'ovirt/statistic'
|
29
|
+
require 'ovirt/storage'
|
30
|
+
require 'ovirt/storage_domain'
|
31
|
+
require 'ovirt/tag'
|
32
|
+
require 'ovirt/template'
|
33
|
+
require 'ovirt/user'
|
34
|
+
require 'ovirt/vm'
|
35
|
+
require 'ovirt/vmpool'
|
data/spec/event_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ovirt::Event do
|
4
|
+
context ".set_event_name" do
|
5
|
+
before :each do
|
6
|
+
@orig_log, $rhevm_log = $rhevm_log, double("logger")
|
7
|
+
end
|
8
|
+
|
9
|
+
after :each do
|
10
|
+
$rhevm_log = @orig_log
|
11
|
+
end
|
12
|
+
|
13
|
+
it "sets the name corresponding to a valid code" do
|
14
|
+
hash = {:code => 1}
|
15
|
+
described_class.send(:set_event_name, hash)
|
16
|
+
hash[:name].should eq Ovirt::Event::EVENT_CODES[1]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets 'UNKNOWN' as the name with an invalid code" do
|
20
|
+
$rhevm_log.should_receive :warn
|
21
|
+
hash = {:code => -1, :description => "Invalid Code"}
|
22
|
+
described_class.send(:set_event_name, hash)
|
23
|
+
hash[:name].should eq "UNKNOWN"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/object_spec.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ovirt::Object do
|
4
|
+
it ".api_endpoint" do
|
5
|
+
Ovirt::Object.api_endpoint.should == "objects"
|
6
|
+
Ovirt::Template.api_endpoint.should == "templates"
|
7
|
+
Ovirt::Cluster.api_endpoint.should == "clusters"
|
8
|
+
Ovirt::Vm.api_endpoint.should == "vms"
|
9
|
+
Ovirt::StorageDomain.api_endpoint.should == "storagedomains"
|
10
|
+
Ovirt::DataCenter.api_endpoint.should == "datacenters"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rest-client'
|
3
|
+
|
4
|
+
describe Ovirt::Service do
|
5
|
+
before do
|
6
|
+
@service = described_class.new(:server => "", :username => "", :password => "")
|
7
|
+
end
|
8
|
+
|
9
|
+
context "#resource_post" do
|
10
|
+
it "raises Ovirt::Error if HTTP 409 response code received" do
|
11
|
+
error_detail = "API error"
|
12
|
+
return_data = <<-EOX.chomp
|
13
|
+
<action>
|
14
|
+
<fault>
|
15
|
+
<detail>#{error_detail}</detail>
|
16
|
+
</fault>
|
17
|
+
</action>
|
18
|
+
EOX
|
19
|
+
|
20
|
+
rest_client = double('rest_client').as_null_object
|
21
|
+
rest_client.should_receive(:post) do |&block|
|
22
|
+
return_data.stub(:code).and_return(409)
|
23
|
+
block.call(return_data)
|
24
|
+
end
|
25
|
+
|
26
|
+
@service.stub(:create_resource).and_return(rest_client)
|
27
|
+
expect { @service.resource_post('uri', 'data') }.to raise_error(Ovirt::Error, error_detail)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
|
11
|
+
# Run specs in random order to surface order dependencies. If you find an
|
12
|
+
# order dependency and want to debug it, you can fix the order by providing
|
13
|
+
# the seed, which is printed after each run.
|
14
|
+
# --seed 1234
|
15
|
+
config.order = 'random'
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'coveralls'
|
20
|
+
Coveralls.wear!
|
21
|
+
rescue LoadError
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'ovirt'
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ovirt::Template do
|
4
|
+
before do
|
5
|
+
@service = double('service')
|
6
|
+
@template = Ovirt::Template.new(@service, {
|
7
|
+
:id => "128f9ffd-b82c-41e4-8c00-9742ed173bac",
|
8
|
+
:href => "/api/vms/128f9ffd-b82c-41e4-8c00-9742ed173bac",
|
9
|
+
:cluster => {
|
10
|
+
:id => "5be5d08a-a60b-11e2-bee6-005056a217db",
|
11
|
+
:href => "/api/clusters/5be5d08a-a60b-11e2-bee6-005056a217db"},
|
12
|
+
:template => {
|
13
|
+
:id => "00000000-0000-0000-0000-000000000000",
|
14
|
+
:href => "/api/templates/00000000-0000-0000-0000-000000000000"},
|
15
|
+
:name => "bd-skeletal-clone-from-template",
|
16
|
+
:origin => "rhev",
|
17
|
+
:type => "server",
|
18
|
+
:memory => 536870912,
|
19
|
+
:stateless => false,
|
20
|
+
:creation_time => "2013-09-04 16:24:20 -0400",
|
21
|
+
:status => {:state => "down"},
|
22
|
+
:display => {:type => "spice", :monitors => 1},
|
23
|
+
:usb => {:enabled => false},
|
24
|
+
:cpu => {:topology => {:sockets => 1, :cores => 1}},
|
25
|
+
:high_availability => {:priority => 1, :enabled => false},
|
26
|
+
:os => {:type => "rhel5_64", :boot_order => [{:dev => "hd"}]},
|
27
|
+
:custom_attributes => [],
|
28
|
+
:placement_policy => {:affinity => "migratable", :host => {}},
|
29
|
+
:memory_policy => {:guaranteed => 536870912},
|
30
|
+
:guest_info => {}
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
context "#create_vm" do
|
35
|
+
it "clones properties for skeletal clones" do
|
36
|
+
options = {:clone_type => :skeletal}
|
37
|
+
expected_data = {
|
38
|
+
:clone_type => :linked,
|
39
|
+
:memory => 536870912,
|
40
|
+
:stateless => false,
|
41
|
+
:type => "server",
|
42
|
+
:display => {:type => "spice", :monitors => 1},
|
43
|
+
:usb => {:enabled => false},
|
44
|
+
:cpu => {:topology => {:sockets => 1, :cores => 1}},
|
45
|
+
:high_availability => {:priority => 1, :enabled => false},
|
46
|
+
:os_type => "rhel5_64"}
|
47
|
+
@template.stub(:nics).and_return([])
|
48
|
+
@template.stub(:disks).and_return([])
|
49
|
+
@service.stub(:blank_template).and_return(double('blank template'))
|
50
|
+
@service.blank_template.should_receive(:create_vm).once.with(expected_data)
|
51
|
+
@template.create_vm(options)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "overrides properties for linked clones" do
|
55
|
+
expected_data = <<-EOX.chomp
|
56
|
+
<vm>
|
57
|
+
<name>new name</name>
|
58
|
+
<cluster id=\"fb27f9a0-cb75-4e0f-8c07-8dec0c5ab483\"/>
|
59
|
+
<template id=\"128f9ffd-b82c-41e4-8c00-9742ed173bac\"/>
|
60
|
+
<memory>536870912</memory>
|
61
|
+
<stateless>false</stateless>
|
62
|
+
<type>server</type>
|
63
|
+
<display>
|
64
|
+
<type>spice</type>
|
65
|
+
<monitors>1</monitors>
|
66
|
+
</display>
|
67
|
+
<usb>
|
68
|
+
<enabled>false</enabled>
|
69
|
+
</usb>
|
70
|
+
<cpu>
|
71
|
+
<topology sockets="1" cores="1"/>
|
72
|
+
</cpu>
|
73
|
+
<high_availability>
|
74
|
+
<priority>1</priority>
|
75
|
+
<enabled>false</enabled>
|
76
|
+
</high_availability>
|
77
|
+
<os type=\"test\">
|
78
|
+
<boot dev=\"hd\"/>
|
79
|
+
</os>
|
80
|
+
</vm>
|
81
|
+
EOX
|
82
|
+
response_xml = <<-EOX.chomp
|
83
|
+
<vm>
|
84
|
+
<os type='foo'/>
|
85
|
+
<placement_policy><affinity>foo</affinity></placement_policy>
|
86
|
+
</vm>
|
87
|
+
EOX
|
88
|
+
options = {
|
89
|
+
:clone_type => :linked,
|
90
|
+
:name => 'new name',
|
91
|
+
:cluster => 'fb27f9a0-cb75-4e0f-8c07-8dec0c5ab483',
|
92
|
+
:os_type => 'test'}
|
93
|
+
@service.should_receive(:resource_post).once.with(:vms, expected_data).and_return(response_xml)
|
94
|
+
@template.create_vm(options)
|
95
|
+
end
|
96
|
+
|
97
|
+
context "#create_new_disks_from_template" do
|
98
|
+
before do
|
99
|
+
@disk = Ovirt::Disk.new(@service, {
|
100
|
+
:id=>"01eae62b-90df-424d-978c-beaa7eb2f7f6",
|
101
|
+
:href=>"/api/templates/54f1b9f4-0e89-4c72-9a26-f94dcb857264/disks/01eae62b-90df-424d-978c-beaa7eb2f7f6",
|
102
|
+
:name=>"clone_Disk1",
|
103
|
+
:storage_domains=>[{:id=>"aa7e70e5-40d0-43e2-a605-92ce6ba652a8"}]
|
104
|
+
})
|
105
|
+
@template.stub(:disks).and_return([@disk])
|
106
|
+
|
107
|
+
@vm = double('rhevm_vm')
|
108
|
+
end
|
109
|
+
|
110
|
+
it "without a storage override" do
|
111
|
+
expected_data = @disk.attributes.dup
|
112
|
+
expected_data[:storage] = expected_data[:storage_domains].first[:id]
|
113
|
+
|
114
|
+
@vm.should_receive(:create_disk).once.with(expected_data)
|
115
|
+
@template.send(:create_new_disks_from_template, @vm, {})
|
116
|
+
end
|
117
|
+
|
118
|
+
it "with a storage override" do
|
119
|
+
expected_data = @disk.attributes.dup
|
120
|
+
options = {:storage => "xxxxxxxx-40d0-43e2-a605-92ce6ba652a8"}
|
121
|
+
expected_data.merge!(options)
|
122
|
+
|
123
|
+
@vm.should_receive(:create_disk).once.with(expected_data)
|
124
|
+
@template.send(:create_new_disks_from_template, @vm, options)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "build_clone_xml" do
|
129
|
+
it "Properly sets vm/cpu/topology attributes" do
|
130
|
+
Object.stub(:object_to_id)
|
131
|
+
xml = @template.send(:build_clone_xml, :name => "Blank", :cluster => "6b8f1c1e-3eb0-11e4-8420-56847afe9799")
|
132
|
+
nodeset = Nokogiri::XML.parse(xml).xpath("//vm/cpu/topology")
|
133
|
+
node = nodeset.first
|
134
|
+
|
135
|
+
expect(nodeset.length).to eq(1)
|
136
|
+
expect(node["cores"].to_i).to eq(1)
|
137
|
+
expect(node["sockets"].to_i).to eq(1)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|