rbovirt 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 37364775867c2c85d2ce024df84520d268709c11
4
- data.tar.gz: cfc11b0e00842a67a37aaf00402313af04f13564
3
+ metadata.gz: 58cb5fab7fdfa1f4dce04d45532618c7415c8be5
4
+ data.tar.gz: ad23cc3fa62db7186b4bf14ae198f5d7e95c74bb
5
5
  SHA512:
6
- metadata.gz: fd9cd881cc6a1da9e596830af2d73af02bd21ef48abd6f29fd0da7428e9297bfdb1d10fe33424f671198ce6a9badd5dbb9c885e504897f70b19050700f067224
7
- data.tar.gz: 2d347cf659fe0f17ede50ed5f99efe143dff113f03f4e0d1484a08b3f65cee14b8da7bc643eabd60444d1a83592366ef138ece1c7245b5d9b54aa4796c1f0e74
6
+ metadata.gz: 22b5ba8ada4d36d8ece11c9be5520188385c6978c80bdee0640b5fe898b559af46a6dd450d4e0b4195e36e3603d027722dc0197fff191c47e01cf789b3d6dde8
7
+ data.tar.gz: 47ba3a1763257b788c3bba4eb5596be1dbed85e36345f4f6a4c7ffaaca9cf97cd96024412020fbcb620f95412c1dd3e85f77e210a0e531f9115645d9c87e0c95
data/CHANGES.rdoc CHANGED
@@ -6,6 +6,28 @@ _rbovirt_ project.
6
6
  Note that this list of changes was added with the 0.0.30 release,
7
7
  previous releases aren't described here.
8
8
 
9
+ == 0.1.1
10
+
11
+ New features:
12
+
13
+ * Support operating systems
14
+ * Added missing brackets for template display
15
+ * Support for using the persistent-auth
16
+ * Add instance types support.
17
+ * Fixes Blank template display
18
+ * Added support for VMS search options max/pages
19
+ * Handle template's disk
20
+ * Fix cloud init for OVirt >= 3.5
21
+ * Set storage domain for template when provided.
22
+ * Include disks in VM XML.
23
+ * Make comment of vm or template editable
24
+ * Adding override_iptables parameter to reinstall_host
25
+ * Implement stricter checks of nicsdef content
26
+ * Implement cloud-init for multiple nics
27
+ * Fix broken OVIRT::Template#volumes
28
+ * Fix for cloudinit so nokogiri correctly processes the files section
29
+ * Add option to set description on VM create.
30
+
9
31
  == 0.1.0 / 2015-05-07
10
32
 
11
33
  New features:
@@ -17,11 +17,17 @@ module OVIRT
17
17
  http_post("/hosts/%s/approve" % host_id, "<action></action>")
18
18
  end
19
19
 
20
- def reinstall_host(host_id, opts={})
20
+ def reinstall_host(host_id, override_iptables=False, opts={})
21
21
  http_post("/hosts/%s/install" % host_id,
22
- "<action><ssh>
23
- <authentication_method>PublicKey</authentication_method>
24
- </ssh></action>")
22
+ "<action>
23
+ <ssh>
24
+ <authentication_method>PublicKey</authentication_method>
25
+ </ssh>
26
+ <host>
27
+ <override_iptables>" + override_iptables + "</override_iptables>
28
+ </host>
29
+ </action>"
30
+ )
25
31
  end
26
32
  end
27
33
  end
@@ -0,0 +1,20 @@
1
+ module OVIRT
2
+ class Client
3
+ def instance_type(instance_type_id)
4
+ begin
5
+ instance_type = http_get("/instancetypes/%s" % instance_type_id)
6
+ OVIRT::InstanceType::new(self, instance_type.root)
7
+ rescue
8
+ handle_fault $!
9
+ end
10
+ end
11
+
12
+ def instance_types(opts={})
13
+ search = opts[:search] ||""
14
+ instance_types = http_get("/instancetypes?search=%s" % CGI.escape(search))
15
+ instance_types.xpath('/instance_types/instance_type').collect do |it|
16
+ OVIRT::InstanceType::new(self, it)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module OVIRT
2
+ class Client
3
+ def operating_systems
4
+ operating_systems = http_get('/operatingsystems')
5
+ operating_systems.xpath('/operating_systems/operating_system').collect do |os|
6
+ OVIRT::OperatingSystem::new(self, os)
7
+ end
8
+ end
9
+ end
10
+ end
data/lib/client/vm_api.rb CHANGED
@@ -6,7 +6,11 @@ module OVIRT
6
6
  end
7
7
 
8
8
  def vms(opts={})
9
- headers = {:accept => "application/xml; detail=disks; detail=nics; detail=hosts"}
9
+ if opts[:without_details]
10
+ headers = {:accept => "application/xml"}
11
+ else
12
+ headers = {:accept => "application/xml; detail=disks; detail=nics; detail=hosts"}
13
+ end
10
14
  path = "/vms"
11
15
  path += search_url(opts) unless filtered_api
12
16
  http_get(path, headers).xpath('/vms/vm').collect do |vm|
@@ -14,6 +18,21 @@ module OVIRT
14
18
  end
15
19
  end
16
20
 
21
+ def process_vm_opts(opts)
22
+ if (opts[:template] or opts[:template_name]) and (opts[:storagedomain] or opts[:storagedomain_name])
23
+ template_id = opts[:template] || templates.select{|t| t.name == opts[:template_name]}.first.id
24
+ template_disks = template_volumes(template_id)
25
+ storagedomain_id = opts[:storagedomain] || storagedomains.select{|s| s.name == opts[:storagedomain_name]}.first.id
26
+
27
+ # Make sure the 'clone' option is set if any of the disks defined by
28
+ # the template is stored on a different storage domain than requested
29
+ opts[:clone] = true unless opts[:clone] == true || template_disks.empty? || template_disks.all? { |d| d.storage_domain == storagedomain_id }
30
+
31
+ # Create disks map
32
+ opts[:disks] = template_disks.collect { |d| {:id => d.id, :storagedomain => storagedomain_id} }
33
+ end
34
+ end
35
+
17
36
  def create_vm(opts)
18
37
  cluster_major_ver, cluster_minor_ver = cluster_version(self.cluster_id)
19
38
 
@@ -32,6 +51,9 @@ module OVIRT
32
51
  raise BackendVersionUnsupportedException.new
33
52
  end
34
53
  end
54
+
55
+ process_vm_opts(opts)
56
+
35
57
  opts[:cluster_name] ||= clusters.first.name unless opts[:cluster]
36
58
  OVIRT::VM::new(self, http_post("/vms",OVIRT::VM.to_xml(opts)).root)
37
59
  end
@@ -122,6 +144,12 @@ module OVIRT
122
144
  end
123
145
 
124
146
  def vm_start_with_cloudinit(id, opts={})
147
+ # Get the api and cluster version on which the VM is provisioned.
148
+ # This is required for VM::cloudinit.
149
+ opts.merge!(
150
+ :cluster_version => cluster_version(vm(id).cluster.id),
151
+ :api_version => api_version.split('.').map(&:to_i)
152
+ )
125
153
  xml = OVIRT::VM.cloudinit(opts)
126
154
  xml_response = http_post("/vms/%s/%s" % [id, 'start'], xml, {} )
127
155
  return (xml_response/'action/status').first.text.strip.upcase=="COMPLETE"
@@ -0,0 +1,73 @@
1
+ module OVIRT
2
+ # Instance types are added to oVirt 3.5 and have been updated in oVirt 3.6
3
+ class InstanceType < BaseObject
4
+ # Common attributes to all oVirt version supported at this time
5
+ attr_reader :name, :description, :memory, :cores, :os, :creation_time
6
+ attr_reader :ha, :ha_priority, :display, :usb, :migration_downtime
7
+
8
+ # oVirt 3.5 attributes
9
+ attr_reader :type, :status, :cpu_shares, :boot_menu, :origin, :stateless
10
+ attr_reader :delete_protected, :sso, :timezone
11
+
12
+ # oVirt 3.6 attributes
13
+ attr_reader :migration, :io_threads, :memory_guaranteed
14
+
15
+ def initialize(client, xml)
16
+ super(client, xml[:id], xml[:href], (xml/'name').first.text)
17
+ parse_xml_attributes!(xml)
18
+ self
19
+ end
20
+
21
+ private
22
+ def parse_xml_attributes!(xml)
23
+ # Common attributes
24
+ @description = ((xml/'description').first.text rescue '')
25
+ @memory = (xml/'memory').first.text
26
+ @cores = ((xml/'cpu/topology').first[:cores].to_i * (xml/'cpu/topology').first[:sockets].to_i rescue nil)
27
+ @os = {
28
+ :type => (xml/'os').first[:type],
29
+ :boot => (xml/'os/boot').collect {|boot| boot[:dev] }
30
+ }
31
+ @creation_time = (xml/'creation_time').text
32
+ @ha = parse_bool((xml/'high_availability/enabled').first.text)
33
+ @ha_priority = ((xml/'high_availability/priority').first.text rescue nil)
34
+ @display = {
35
+ :type => (xml/'display/type').first.text,
36
+ :monitors => (xml/'display/monitors').first.text,
37
+ :single_qxl_pci => parse_bool((xml/'display/single_qxl_pci').first.text),
38
+ :smartcard_enabled => parse_bool((xml/'display/smartcard_enabled').first.text),
39
+
40
+ }
41
+ @usb = parse_bool((xml/'usb/enabled').first.text)
42
+ @migration_downtime = ((xml/'migration_downtime').first.text)
43
+
44
+ # oVirt 3.5 attributes
45
+ @type = ((xml/'type').first.text rescue nil)
46
+ @status = ((xml/'status').first.text rescue nil)
47
+ @cpu_shares = (((xml/'cpu_shares').first.text) rescue nil)
48
+ potential_bool = ((xml/'bios/boot_menu/enabled').first.text rescue nil)
49
+ @boot_menu = potential_bool.nil? ? nil : parse_bool(potential_bool)
50
+ @origin = ((xml/'origin').text rescue nil)
51
+ potential_bool = ((xml/'stateless').first.text rescue nil)
52
+ @stateless = potential_bool.nil? ? nil : parse_bool(potential_bool)
53
+ potential_bool = ((xml/'delete_protected').first.text rescue nil)
54
+ @delete_protected = potential_bool.nil? ? nil : parse_bool(potential_bool)
55
+ #@sso = ((xml/'sso/methods').first.text rescue nil)
56
+ @timezone = ((xml/'timezone').first.text rescue nil)
57
+ potential_bool = ((xml/'display/allow_override').first.text rescue nil)
58
+ @display[:allow_override] = potential_bool.nil? ? nil : parse_bool(potential_bool)
59
+ potential_bool = ((xml/'display/file_transfer_enabled').first.text rescue nil)
60
+ @display[:file_transfer_enabled] = potential_bool.nil? ? nil : parse_bool(potential_bool)
61
+ potential_bool = ((xml/'display/copy_paste_enabled').first.text rescue nil)
62
+ @display[:copy_paste_enabled] = potential_bool.nil? ? nil : parse_bool(potential_bool)
63
+
64
+ # oVirt 3.6 attributes
65
+ @migration = {
66
+ :auto_converge => ((xml/'migration/auto_converge').first.text rescue nil),
67
+ :compressed => ((xml/'migration/compressed').first.text rescue nil)
68
+ }
69
+ @io_threads = ((xml/'io/threads').first.text rescue nil)
70
+ @memory_guaranteed = ((xml/'memory_policy/guaranteed').first.text rescue nil)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,11 @@
1
+ module OVIRT
2
+ class OperatingSystem < BaseObject
3
+ attr_reader :description
4
+
5
+ def initialize(client, xml)
6
+ super(client, xml[:id], xml[:href], (xml/'name').text)
7
+ @description = (xml/'description').text
8
+ self
9
+ end
10
+ end
11
+ end
@@ -1,6 +1,7 @@
1
1
  module OVIRT
2
2
  class Template < BaseObject
3
- attr_reader :description, :comment, :status, :cluster, :creation_time, :os, :storage, :display, :profile, :memory, :version
3
+ attr_reader :description, :status, :cluster, :creation_time, :os, :storage, :display, :profile, :memory, :version
4
+ attr_accessor :comment
4
5
 
5
6
  def initialize(client, xml)
6
7
  super(client, xml[:id], xml[:href], (xml/'name').first.text)
@@ -25,7 +26,7 @@ module OVIRT
25
26
  end
26
27
 
27
28
  def volumes
28
- @volumes ||= @client.send(:volumes, "/templates/%s/disks" % id)
29
+ @volumes ||= @client.template_volumes(id)
29
30
  end
30
31
 
31
32
  private
@@ -38,8 +39,8 @@ module OVIRT
38
39
  @profile = (xml/'type').first.text
39
40
  @cluster = Link::new(@client, (xml/'cluster').first[:id], (xml/'cluster').first[:href])
40
41
  @display = {
41
- :type => (xml/'display/type').first.text,
42
- :monitors => (xml/'display/monitors').first.text
42
+ :type => ((xml/'display/type').first.text rescue ''),
43
+ :monitors => ((xml/'display/monitors').first.text rescue 0)
43
44
  }
44
45
  @cores = ((xml/'cpu/topology').first[:cores].to_i * (xml/'cpu/topology').first[:sockets].to_i rescue nil)
45
46
  @storage = ((xml/'disks/disk/size').first.text rescue nil)
@@ -8,7 +8,7 @@ module OVIRT
8
8
  def parse_xml_attributes(xml)
9
9
  @base_template = (xml/"base_template").first[:id]
10
10
  @version_number = (xml/"version_number").first.text
11
- @version_name = (xml/"version_name").first.text
11
+ @version_name = ((xml/"version_name").first.text rescue nil)
12
12
  end
13
13
  end
14
- end
14
+ end
data/lib/ovirt/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module OVIRT
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/ovirt/vm.rb CHANGED
@@ -4,9 +4,9 @@ module OVIRT
4
4
  FILEINJECT_PATH = "user-data.txt"
5
5
 
6
6
  class VM < BaseObject
7
- attr_reader :description, :comment, :status, :memory, :profile, :display, :host, :cluster, :template
7
+ attr_reader :description, :status, :memory, :profile, :display, :host, :cluster, :template
8
8
  attr_reader :storage, :cores, :creation_time, :os, :ha, :ha_priority, :ips, :vnc, :quota, :clone
9
- attr_accessor :interfaces, :volumes
9
+ attr_accessor :comment, :interfaces, :volumes
10
10
 
11
11
  def initialize(client, xml)
12
12
  super(client, xml[:id], xml[:href], (xml/'name').first.text)
@@ -50,6 +50,7 @@ module OVIRT
50
50
  builder = Nokogiri::XML::Builder.new do
51
51
  vm{
52
52
  name_ opts[:name] || "i-#{Time.now.to_i}"
53
+ description_ opts[:description] || ""
53
54
  if opts[:comment]
54
55
  comment_ opts[:comment]
55
56
  end
@@ -79,18 +80,23 @@ module OVIRT
79
80
  end
80
81
  # os element must not be sent when template is present (RHBZ 1104235)
81
82
  if opts[:template].nil? || opts[:template].empty?
82
- os({:type => opts[:os_type] || 'unassigned' }){
83
- if(opts[:first_boot_dev] && opts[:first_boot_dev] == 'network')
84
- boot(:dev=> opts[:boot_dev1] || 'network')
85
- boot(:dev=> opts[:boot_dev2] || 'hd')
86
- else
87
- boot(:dev=> opts[:boot_dev2] || 'hd')
88
- boot(:dev=> opts[:boot_dev1] || 'network')
83
+ os_opts = opts[:os] ? opts[:os].dup : {}
84
+ os_opts[:type] ||= opts[:os_type] || 'unassigned'
85
+ os_opts[:boot] ||= [opts.fetch(:boot_dev1, 'network'), opts.fetch(:boot_dev2, 'hd')]
86
+ os_opts[:kernel] ||= opts[:os_kernel]
87
+ os_opts[:initrd] ||= opts[:os_initrd]
88
+ os_opts[:cmdline] ||= opts[:os_cmdline]
89
+ if opts[:first_boot_dev]
90
+ os_opts[:boot] = os_opts[:boot].sort_by.with_index do |device, index|
91
+ device == opts[:first_boot_dev] ? -1 : index
89
92
  end
90
- kernel (opts[:os_kernel])
91
- initrd (opts[:os_initrd])
92
- cmdline (opts[:os_cmdline])
93
- }
93
+ end
94
+ os(:type => os_opts[:type]) do
95
+ os_opts[:boot].each { |device| boot(:dev => device) }
96
+ kernel os_opts[:kernel]
97
+ initrd os_opts[:initrd]
98
+ cmdline os_opts[:cmdline]
99
+ end
94
100
  end
95
101
  if !opts[:ha].nil? || !opts[:ha_priority].nil?
96
102
  high_availability_{
@@ -98,7 +104,16 @@ module OVIRT
98
104
  priority_(opts[:ha_priority]) unless opts[:ha_priority].nil?
99
105
  }
100
106
  end
101
- disks_ { clone_(opts[:clone]) } if opts[:clone]
107
+ disks_ {
108
+ clone_(opts[:clone]) if opts[:clone]
109
+ if opts[:disks]
110
+ opts[:disks].each do |d|
111
+ disk(:id => d[:id]) {
112
+ storage_domains { storage_domain(:id => d[:storagedomain]) }
113
+ }
114
+ end
115
+ end
116
+ }
102
117
  display_{
103
118
  type_(opts[:display][:type])
104
119
  } if opts[:display]
@@ -136,11 +151,14 @@ module OVIRT
136
151
  gateway = opts[:gateway]
137
152
  domain = opts[:domain]
138
153
  nicname = opts[:nicname]
154
+ nicsdef = opts[:nicsdef]
139
155
  user = opts[:user] || 'root'
140
156
  password = opts[:password]
141
157
  ssh_authorized_keys = opts[:ssh_authorized_keys]
142
158
  fileslist = opts[:files]
143
159
  runcmd = opts[:runcmd]
160
+ cluster_major, cluster_minor = opts[:cluster_version]
161
+ api_major,api_minor, api_build, api_revision = opts[:api_version]
144
162
  extracmd = nil
145
163
  unless opts[:phone_home].nil?
146
164
  phone_home = \
@@ -164,6 +182,23 @@ module OVIRT
164
182
  end
165
183
  builder = Nokogiri::XML::Builder.new do
166
184
  action {
185
+ # An API has changed in version 3.5.5. Make sure
186
+ # <use_cloud_init>true</use_cloud_init> is used only if the endpoint
187
+ # if of that version or higher and the cluster the VM is provisioned
188
+ # to is of version 3.5 or higher.
189
+ # NOTE: RHEV-m/OVirt versions prior to 3.6.0 contain a bug
190
+ # (https://bugzilla.redhat.com/show_bug.cgi?id=1206068) which causes
191
+ # that build and revision parameters ov API version are set to 0.
192
+ # This may have an impact on conditional inclusion of <use_cloud_init>
193
+ # and thus leaving the guest unconfigured.
194
+ # You can either upgrade to RHEV-m/OVirt 3.6+ or work this around by
195
+ # manually forcing the ovirt engine to report an appropriate version:
196
+ # % rhevm-config -s VdcVersion=<major>.<minor>.<build>.<revision>
197
+ # % service ovirt-engine restart
198
+ # Please replace the placeholders with appropriate values.
199
+ if api_major > 3 || (api_major == 3 && api_minor > 5) || (api_major == 3 && api_minor == 5 && api_build >= 5)
200
+ use_cloud_init true if cluster_major > 3 || (cluster_major == 3 && cluster_minor >= 5)
201
+ end
167
202
  vm {
168
203
  initialization {
169
204
  unless runcmd.nil?
@@ -194,18 +229,35 @@ module OVIRT
194
229
  }
195
230
  }
196
231
  end
197
- network_configuration {
198
- unless nicname.nil?
232
+ network_configuration {
233
+ if !nicname.nil?
199
234
  nics {
200
235
  nic {
201
- name_ nicname
236
+ name_ nicname
202
237
  unless ip.nil? || netmask.nil? || gateway.nil?
203
238
  network { ip(:'address'=> ip , :'netmask'=> netmask, :'gateway'=> gateway ) }
204
239
  boot_protocol 'STATIC'
205
240
  on_boot 'true'
206
241
  end
207
242
  }
208
- }
243
+ }
244
+ elsif nicsdef.is_a?(Array) && !nicsdef.empty? && nicsdef.all? { |n| n.is_a?(Hash) }
245
+ nics {
246
+ nicsdef.each do |n|
247
+ nic {
248
+ name_(n[:nicname])
249
+ boot_protocol_(n[:boot_protocol] || 'NONE') # Defaults to NONE boot proto
250
+ on_boot_(n[:on_boot] || 'true') # Defaults to 'true'
251
+ unless n[:ip].nil? || n[:netmask].nil?
252
+ network_ {
253
+ n[:gateway].nil? ?
254
+ ip_(:address => n[:ip], :netmask => n[:netmask]) :
255
+ ip_(:address => n[:ip], :netmask => n[:netmask], :gateway => n[:gateway])
256
+ }
257
+ end
258
+ }
259
+ end
260
+ }
209
261
  end
210
262
  dns {
211
263
  unless dns.nil?
@@ -223,7 +275,7 @@ module OVIRT
223
275
  regenerate_ssh_keys 'true'
224
276
  files {
225
277
  unless extracmd.nil?
226
- file {
278
+ file_ {
227
279
  name_ 'ignored'
228
280
  content extracmd
229
281
  type 'PLAINTEXT'
@@ -259,12 +311,12 @@ module OVIRT
259
311
  @host = Link::new(@client, (xml/'host').first[:id], (xml/'host').first[:href]) rescue nil
260
312
  @cluster = Link::new(@client, (xml/'cluster').first[:id], (xml/'cluster').first[:href])
261
313
  @display = {
262
- :type => (xml/'display/type').first.text,
314
+ :type => ((xml/'display/type').first.text rescue ''),
263
315
  :address => ((xml/'display/address').first.text rescue nil),
264
316
  :port => ((xml/'display/port').first.text rescue nil),
265
317
  :secure_port => ((xml/'display/secure_port').first.text rescue nil),
266
318
  :subject => ((xml/'display/certificate/subject').first.text rescue nil),
267
- :monitors => (xml/'display/monitors').first.text
319
+ :monitors => ((xml/'display/monitors').first.text rescue 0)
268
320
  }
269
321
  @cores = ((xml/'cpu/topology').first[:cores].to_i * (xml/'cpu/topology').first[:sockets].to_i rescue nil)
270
322
  @storage = ((xml/'disks/disk/size').first.text rescue nil)
data/lib/rbovirt.rb CHANGED
@@ -12,7 +12,9 @@ require "ovirt/interface"
12
12
  require "ovirt/network"
13
13
  require "ovirt/quota"
14
14
  require "ovirt/affinity_group"
15
+ require "ovirt/instance_type"
15
16
  require "ovirt/version"
17
+ require "ovirt/operating_system"
16
18
 
17
19
  require "client/vm_api"
18
20
  require "client/template_api"
@@ -24,6 +26,8 @@ require "client/quota_api"
24
26
  require "client/disk_api"
25
27
  require "client/affinity_group_api"
26
28
  require "client/disk_profile_api"
29
+ require "client/instance_type_api"
30
+ require "client/operating_system_api"
27
31
 
28
32
  require "nokogiri"
29
33
  require "rest_client"
@@ -45,7 +49,7 @@ module OVIRT
45
49
 
46
50
  class Client
47
51
 
48
- attr_reader :credentials, :api_entrypoint, :datacenter_id, :cluster_id, :filtered_api, :ca_cert_file, :ca_cert_store, :ca_no_verify
52
+ attr_reader :credentials, :api_entrypoint, :datacenter_id, :cluster_id, :filtered_api, :ca_cert_file, :ca_cert_store, :ca_no_verify, :persistent_auth, :jsessionid
49
53
 
50
54
  # Construct a new ovirt client class.
51
55
  # mandatory parameters
@@ -67,20 +71,26 @@ module OVIRT
67
71
  :cluster_id => backward_compatibility_cluster,
68
72
  :filtered_api => backward_compatibility_filtered}
69
73
  end
70
- @api_entrypoint = api_entrypoint
71
- @credentials = { :username => username, :password => password }
72
- @datacenter_id = options[:datacenter_id]
73
- @cluster_id = options[:cluster_id]
74
- @filtered_api = options[:filtered_api]
75
- @ca_cert_file = options[:ca_cert_file]
76
- @ca_cert_store = options[:ca_cert_store]
77
- @ca_no_verify = options[:ca_no_verify]
74
+ @api_entrypoint = api_entrypoint
75
+ @credentials = { :username => username, :password => password }
76
+ @datacenter_id = options[:datacenter_id]
77
+ @cluster_id = options[:cluster_id]
78
+ @filtered_api = options[:filtered_api]
79
+ @ca_cert_file = options[:ca_cert_file]
80
+ @ca_cert_store = options[:ca_cert_store]
81
+ @ca_no_verify = options[:ca_no_verify]
82
+ @persistent_auth = options[:persistent_auth]
83
+ @jsessionid = options[:jsessionid]
78
84
  end
79
85
 
80
86
  def api_version
81
87
  return @api_version unless @api_version.nil?
82
88
  xml = http_get("/")/'/api/product_info/version'
83
- @api_version = (xml/'version').first[:major] +"."+ (xml/'version').first[:minor]
89
+ major = (xml/'version').first[:major]
90
+ minor = (xml/'version').first[:minor]
91
+ build = (xml/'version').first[:build]
92
+ revision = (xml/'version').first[:revision]
93
+ @api_version = "#{major}.#{minor}.#{build}.#{revision}"
84
94
  end
85
95
 
86
96
  def api_version?(major, minor=nil)
@@ -93,9 +103,13 @@ module OVIRT
93
103
  end
94
104
 
95
105
  private
106
+
96
107
  def search_url opts
97
- search = opts[:search] || ("datacenter=%s" % current_datacenter.name)
98
- "?search=%s" % CGI.escape(search)
108
+ search = opts[:search] || ''
109
+ search += " datacenter=\"%s\"" % current_datacenter.name
110
+ search += " page #{opts[:page]}" if opts[:page]
111
+ max = opts[:max] ? ";max=#{opts[:max]}" : ''
112
+ "#{max}?search=#{CGI.escape(search)}"
99
113
  end
100
114
 
101
115
  def current_datacenter
@@ -108,9 +122,7 @@ module OVIRT
108
122
 
109
123
  def http_get(suburl, headers={})
110
124
  begin
111
- res = rest_client(suburl).get(http_headers(headers))
112
- puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
113
- Nokogiri::XML(res)
125
+ handle_success(rest_client(suburl).get(http_headers(headers)))
114
126
  rescue
115
127
  handle_fault $!
116
128
  end
@@ -118,9 +130,7 @@ module OVIRT
118
130
 
119
131
  def http_post(suburl, body, headers={})
120
132
  begin
121
- res = rest_client(suburl).post(body, http_headers(headers))
122
- puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
123
- Nokogiri::XML(res)
133
+ handle_success(rest_client(suburl).post(body, http_headers(headers)))
124
134
  rescue
125
135
  handle_fault $!
126
136
  end
@@ -128,9 +138,7 @@ module OVIRT
128
138
 
129
139
  def http_put(suburl, body, headers={})
130
140
  begin
131
- res = rest_client(suburl).put(body, http_headers(headers))
132
- puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
133
- Nokogiri::XML(res)
141
+ handle_success(rest_client(suburl).put(body, http_headers(headers)))
134
142
  rescue
135
143
  handle_fault $!
136
144
  end
@@ -140,9 +148,7 @@ module OVIRT
140
148
  begin
141
149
  headers = body ? http_headers(headers) :
142
150
  {:accept => 'application/xml'}.merge(auth_header).merge(filter_header)
143
- res = rest_client(suburl).delete_with_payload(body, headers)
144
- puts "#{res}\n" if ENV['RBOVIRT_LOG_RESPONSE']
145
- Nokogiri::XML(res)
151
+ handle_success(rest_client(suburl).delete_with_payload(body, headers))
146
152
  rescue
147
153
  handle_fault $!
148
154
  end
@@ -151,7 +157,12 @@ module OVIRT
151
157
  def auth_header
152
158
  # This is the method for strict_encode64:
153
159
  encoded_credentials = ["#{@credentials[:username]}:#{@credentials[:password]}"].pack("m0").gsub(/\n/,'')
154
- { :authorization => "Basic " + encoded_credentials }
160
+ headers = { :authorization => "Basic " + encoded_credentials }
161
+ if persistent_auth
162
+ headers[:prefer] = 'persistent-auth'
163
+ headers[:cookie] = "JSESSIONID=#{jsessionid}" if jsessionid
164
+ end
165
+ headers
155
166
  end
156
167
 
157
168
  def rest_client(suburl)
@@ -189,6 +200,12 @@ module OVIRT
189
200
  }).merge(headers)
190
201
  end
191
202
 
203
+ def handle_success(response)
204
+ puts "#{response}\n" if ENV['RBOVIRT_LOG_RESPONSE']
205
+ @jsessionid ||= response.cookies['JSESSIONID']
206
+ Nokogiri::XML(response)
207
+ end
208
+
192
209
  def handle_fault(f)
193
210
  if f.is_a?(RestClient::BadRequest) || f.is_a?(RestClient::Conflict)
194
211
  fault = (Nokogiri::XML(f.http_body)/'//fault/detail')
@@ -58,6 +58,28 @@ describe OVIRT, "Https authentication" do
58
58
  end
59
59
  end
60
60
 
61
+ describe OVIRT, "Persistent authentication" do
62
+ context 'use persistent authentication' do
63
+
64
+ it "test_request_with_persistent_authentication" do
65
+ user, password, url, datacenter = endpoint
66
+ cert = ca_cert(url)
67
+ store = OpenSSL::X509::Store.new().add_cert(
68
+ OpenSSL::X509::Certificate.new(cert))
69
+
70
+ client = ::OVIRT::Client.new(user, password, url, {:ca_cert_store => store, :persistent_auth => true})
71
+ client.api_version.class.should eql(String)
72
+ client.persistent_auth.should eql(true)
73
+ client.jsessionid.should_not be_nil
74
+
75
+ # When performing a new request the jsessionid should remain the same
76
+ orig_jsession_id = client.jsessionid
77
+ client.datacenters.class.should eql(Array)
78
+ client.jsessionid.should eql(orig_jsession_id)
79
+ end
80
+ end
81
+ end
82
+
61
83
  describe OVIRT, "Admin API" do
62
84
 
63
85
  before(:all) do
@@ -97,3 +119,22 @@ describe OVIRT, "User API" do
97
119
  end
98
120
 
99
121
  end
122
+
123
+ describe OVIRT, "Operating systems API" do
124
+
125
+ before(:all) do
126
+ setup_client
127
+ end
128
+
129
+ context 'basic user api and listing' do
130
+ it "exposes supported operating systems" do
131
+ oses = @client.operating_systems
132
+ oses.should_not be_empty
133
+ os = oses.first
134
+ os.id.should_not be_empty
135
+ os.name.should_not be_empty
136
+ os.description.should_not be_empty
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,16 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ describe "Basic Instance type life cycle" do
4
+ before(:all) do
5
+ setup_client
6
+ end
7
+
8
+ it "test_should_return_instance_types" do
9
+ @client.instance_types
10
+ end
11
+
12
+ it "test_should_return_an_instance_type" do
13
+ @instance_type = @client.instance_types.first
14
+ @client.instance_type(@instance_type.id).id.should eql(@instance_type.id)
15
+ end
16
+ end
@@ -51,6 +51,8 @@ shared_examples_for "Basic VM Life cycle" do
51
51
  end
52
52
 
53
53
  it "test_should_set_vm_ticket" do
54
+ while @client.vm(@vm.id).status.strip != 'down' do
55
+ end
54
56
  @client.vm_action(@vm.id, :start)
55
57
  while !@client.vm(@vm.id).running? do
56
58
  end
@@ -117,6 +119,7 @@ shared_examples_for "VM Life cycle without template" do
117
119
  end
118
120
  end
119
121
 
122
+
120
123
  describe "Admin API VM Life cycle" do
121
124
 
122
125
  before(:all) do
@@ -149,3 +152,124 @@ describe "User API VM Life cycle" do
149
152
  it_behaves_like "Basic VM Life cycle"
150
153
  end
151
154
  end
155
+
156
+ describe "VM API support functions" do
157
+
158
+ before(:all) do
159
+ setup_client
160
+ if @client.templates.empty?
161
+ name = 'vm-'+Time.now.to_i.to_s
162
+ @cluster = @client.clusters.select{|c| c.name == cluster_name}.first.id
163
+ vm = @client.create_vm(:name => name, :cluster => @cluster)
164
+ @client.add_volume(vm.id)
165
+ @client.add_interface(vm.id, :network_name => network_name)
166
+ while !@client.vm(vm.id).ready? do
167
+ end
168
+ @client.create_template(:vm => vm.id, :name => "template-#{name}", :description => "test_template", :comment => "test_template")
169
+ end
170
+
171
+ @template_name = @config['template'] || @client.templates.first.name
172
+ @template = @client.templates.find { |t| t.name == @template_name }.id
173
+ @template_disks = @client.template_volumes(@template)
174
+ @storagedomain = @client.storagedomains.first.id
175
+ @storagedomain_name = @client.storagedomains.first.name
176
+ end
177
+
178
+ context 'options processing' do
179
+ it "should process template option into disk decriptions" do
180
+ t_id = @template
181
+ opts = {:template => t_id}
182
+ t_name = opts[:template_name]
183
+ @client.process_vm_opts(opts)
184
+ opts[:template].should eql(t_id)
185
+ opts[:template_name].should eql(t_name)
186
+ end
187
+
188
+ it "should process template_name option into disk decriptions" do
189
+ t_name = @template_name
190
+ opts = {:template_name => t_name}
191
+ t_id = opts[:template]
192
+ @client.process_vm_opts(opts)
193
+ opts[:template].should eql(t_id)
194
+ opts[:template_name].should eql(t_name)
195
+ end
196
+
197
+ it "should process template and storagedomain options into disk decriptions" do
198
+ t_id = @template
199
+ s_id = @storagedomain
200
+ opts = {:template => t_id,
201
+ :storagedomain => s_id}
202
+ t_name = opts[:template_name]
203
+ s_name = opts[:storagedomain_name]
204
+ @client.process_vm_opts(opts)
205
+ opts[:disks].length.should eql(@template_disks.length)
206
+ unless @template_disks.empty?
207
+ opts[:disks].first[:id].should_not be_nil
208
+ opts[:disks].first[:storagedomain].should eql(s_id)
209
+ end
210
+ opts[:template].should eql(t_id)
211
+ opts[:template_name].should eql(t_name)
212
+ opts[:storagedomain].should eql(s_id)
213
+ opts[:storagedomain_name].should eql(s_name)
214
+ end
215
+
216
+ it "should process template_name and storagedomain options into disk decriptions" do
217
+ t_name = @template_name
218
+ s_id = @storagedomain
219
+ opts = {:template_name => t_name,
220
+ :storagedomain => s_id}
221
+ t_id = opts[:template]
222
+ s_name = opts[:storagedomain_name]
223
+ @client.process_vm_opts(opts)
224
+ opts[:disks].length.should eql(@template_disks.length)
225
+ unless @template_disks.empty?
226
+ opts[:disks].first[:id].should_not be_nil
227
+ opts[:disks].first[:storagedomain].should eql(s_id)
228
+ end
229
+ opts[:template].should eql(t_id)
230
+ opts[:template_name].should eql(t_name)
231
+ opts[:storagedomain].should eql(s_id)
232
+ opts[:storagedomain_name].should eql(s_name)
233
+ end
234
+
235
+ it "should process template and storagedomain_name options into disk decriptions" do
236
+ t_id = @template
237
+ s_name = @storagedomain_name
238
+ opts = {:template => t_id,
239
+ :storagedomain_name => s_name}
240
+ t_name = opts[:template_name]
241
+ s_id = opts[:storagedomain_id]
242
+ @client.process_vm_opts(opts)
243
+ opts[:disks].length.should eql(@template_disks.length)
244
+ unless @template_disks.empty?
245
+ opts[:disks].first[:id].should_not be_nil
246
+ opts[:disks].first[:storagedomain].should eql(@storagedomain)
247
+ end
248
+ opts[:template].should eql(t_id)
249
+ opts[:template_name].should eql(t_name)
250
+ opts[:storagedomain].should eql(s_id)
251
+ opts[:storagedomain_name].should eql(s_name)
252
+ end
253
+
254
+ it "should process template_name and storagedomain_name options into disk decriptions" do
255
+ t_name = @template_name
256
+ s_name = @storagedomain_name
257
+ opts = {:template_name => t_name,
258
+ :storagedomain_name => s_name}
259
+ t_id = opts[:template]
260
+ s_id = opts[:storagedomain]
261
+ @client.process_vm_opts(opts)
262
+ opts[:disks].length.should eql(@template_disks.length)
263
+ unless @template_disks.empty?
264
+ opts[:disks].first[:id].should_not be_nil
265
+ opts[:disks].first[:storagedomain].should eql(@storagedomain)
266
+ end
267
+ opts[:template].should eql(t_id)
268
+ opts[:template_name].should eql(t_name)
269
+ opts[:storagedomain].should eql(s_id)
270
+ opts[:storagedomain_name].should eql(s_name)
271
+ end
272
+
273
+ end
274
+ end
275
+
data/spec/unit/vm_spec.rb CHANGED
@@ -232,6 +232,50 @@ END_HEREDOC
232
232
  xml.nil?.should eql(false)
233
233
  end
234
234
 
235
+ it "create vm xml without description" do
236
+ opts = {
237
+ :cluster_name =>'cluster',
238
+ :template_name =>'template',
239
+ }
240
+ xml = OVIRT::VM.to_xml(opts)
241
+ xml.nil?.should eql(false)
242
+ Nokogiri::XML(xml).xpath("//description").length.should eql(1)
243
+ Nokogiri::XML(xml).xpath("//description")[0].children.length.should eql(0)
244
+ end
245
+
246
+ it "create vm xml with description" do
247
+ opts = {
248
+ :cluster_name =>'cluster',
249
+ :template_name =>'template',
250
+ :description => 'a description',
251
+ }
252
+ xml = OVIRT::VM.to_xml(opts)
253
+ xml.nil?.should eql(false)
254
+ Nokogiri::XML(xml).xpath("//description").length.should eql(1)
255
+ Nokogiri::XML(xml).xpath("//description")[0].children.length.should eql(1)
256
+ Nokogiri::XML(xml).xpath("//description")[0].children[0].text?.should eql(true)
257
+ Nokogiri::XML(xml).xpath("//description")[0].content.should eql("a description")
258
+ end
259
+
260
+ it "create vm xml with disks" do
261
+ disk = "00000000-0000-0000-0000-000000000000"
262
+ storagedomain = "00000000-0000-0000-0000-000000000001"
263
+ disks = [{:id => disk, :storagedomain => storagedomain}]
264
+ opts = {
265
+ :cluster_name => 'cluster',
266
+ :disks => disks,
267
+ }
268
+ xml = OVIRT::VM.to_xml(opts)
269
+ puts xml
270
+ xml.nil?.should eql(false)
271
+ Nokogiri::XML(xml).xpath("//disks").length.should eql(1)
272
+ Nokogiri::XML(xml).xpath("//disks")[0].element_children.length.should eql(1)
273
+ Nokogiri::XML(xml).xpath("//disks/disk[contains(@id,'#{disk}')]").length.should eql(1)
274
+ Nokogiri::XML(xml).xpath("//disks/disk/storage_domains").length.should eql(1)
275
+ Nokogiri::XML(xml).xpath("//disks/disk/storage_domains")[0].element_children.length.should eql(1)
276
+ Nokogiri::XML(xml).xpath("//disks/disk/storage_domains/storage_domain[contains(@id,'#{storagedomain}')]").length.should eql(1)
277
+ end
278
+
235
279
  it "should be running" do
236
280
  vm = OVIRT::VM.new(nil, Nokogiri::XML(@xml).xpath('/').first)
237
281
  vm.running?.should eql(true)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbovirt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amos Benari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-07 00:00:00.000000000 Z
11
+ date: 2016-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -80,8 +80,7 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: |2
84
- A Ruby client for oVirt REST API
83
+ description: " A Ruby client for oVirt REST API\n"
85
84
  email:
86
85
  - abenari@redhat.com
87
86
  executables: []
@@ -103,6 +102,8 @@ files:
103
102
  - lib/client/disk_api.rb
104
103
  - lib/client/disk_profile_api.rb
105
104
  - lib/client/host_api.rb
105
+ - lib/client/instance_type_api.rb
106
+ - lib/client/operating_system_api.rb
106
107
  - lib/client/quota_api.rb
107
108
  - lib/client/storage_domain_api.rb
108
109
  - lib/client/template_api.rb
@@ -113,8 +114,10 @@ files:
113
114
  - lib/ovirt/datacenter.rb
114
115
  - lib/ovirt/disk_profile.rb
115
116
  - lib/ovirt/host.rb
117
+ - lib/ovirt/instance_type.rb
116
118
  - lib/ovirt/interface.rb
117
119
  - lib/ovirt/network.rb
120
+ - lib/ovirt/operating_system.rb
118
121
  - lib/ovirt/quota.rb
119
122
  - lib/ovirt/storage_domain.rb
120
123
  - lib/ovirt/template.rb
@@ -127,6 +130,7 @@ files:
127
130
  - rbovirt.gemspec
128
131
  - spec/endpoint.yml.example
129
132
  - spec/integration/api_spec.rb
133
+ - spec/integration/instance_type_spec.rb
130
134
  - spec/integration/vm_crud_spec.rb
131
135
  - spec/spec_helper.rb
132
136
  - spec/unit/client_spec.rb
@@ -157,14 +161,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
161
  version: '0'
158
162
  requirements: []
159
163
  rubyforge_project:
160
- rubygems_version: 2.2.2
164
+ rubygems_version: 2.0.14
161
165
  signing_key:
162
166
  specification_version: 4
163
167
  summary: A Ruby client for oVirt REST API
164
168
  test_files:
165
169
  - spec/endpoint.yml.example
166
170
  - spec/integration/api_spec.rb
171
+ - spec/integration/instance_type_spec.rb
167
172
  - spec/integration/vm_crud_spec.rb
168
173
  - spec/spec_helper.rb
169
174
  - spec/unit/client_spec.rb
170
175
  - spec/unit/vm_spec.rb
176
+ has_rdoc: