rbovirt 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: