ruby-libvirt 0.2.0 → 0.3.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.
data/NEWS CHANGED
@@ -1,3 +1,46 @@
1
+ 2010-12-12 0.3.0
2
+ * Implementation of Libvirt::open_auth, Libvirt::event_register_impl
3
+ * Updated Connect class, implementing conn.compare_cpu, conn.baseline_cpu,
4
+ conn.domain_event_register_any, conn.domain_event_deregister_any,
5
+ conn.domain_event_register, conn.domain_event_deregister, and
6
+ conn.create_domain_xml.
7
+ * Updated Domain class, implementing dom.get_vcpus, dom.update_device,
8
+ dom.scheduler_type, dom.scheduler_parameters, dom.scheduler_parameters=,
9
+ dom.num_vcpus, dom.vcpus_flags=, and dom.qemu_monitor_command.
10
+ * Updated Interface class, implementing interface.free
11
+ * Many potential memory leaks have been fixed.
12
+ * Many bugfixes.
13
+ * Documentation update of many methods, including all of the lookup methods
14
+ that were missing before.
15
+
16
+ 2010-11-10
17
+ * Gem for version 0.2.0 pushed to rubygems.org
18
+
19
+ 2010-07-01 0.2.0
20
+ * Updated Storage class, implementing pool.active?, pool.persistent?,
21
+ pool.vol_create_xml_from.
22
+ * Updated Connect class, implementing conn.node_free_memory,
23
+ conn.node_cells_free_memory, conn.node_get_security_model, conn.encrypted?,
24
+ conn.libversion, and conn.secure?
25
+ * Updated Network class, implementing network.active? and network.persistent?
26
+ * Update Domain class, implementing conn.domain_xml_from_native,
27
+ conn.domain_xml_to_native, dom.migrate_to_uri,
28
+ dom.migrate_set_max_downtime, dom.managed_save, dom.has_managed_save?,
29
+ dom.managed_save_remove, dom.security_label, dom.block_stats,
30
+ dom.memory_stats, dom.blockinfo, dom.block_peek, dom.memory_peek,
31
+ dom.active?, dom.persistent?, dom.snapshot_create_xml,
32
+ dom.num_of_snapshots, dom.list_snapshots, dom.lookup_snapshot_by_name,
33
+ dom.has_current_snapshot?, dom.revert_to_snapshot, dom.current_snapshot,
34
+ snapshot.xml_desc, snapshot.delete, dom.job_info, and dom.abort_job.
35
+ * Implementation of the NodeDevice class.
36
+ * Implementation of the Secret class.
37
+ * Implementation of the NWFilter class.
38
+ * Implementation of the Interface class.
39
+ * Conversion of the development tree to git.
40
+ * New maintainer (Chris Lalancette). David Lutterkort has agreed to transfer
41
+ maintainership since he is not actively involved in their development
42
+ anymore.
43
+
1
44
  2008-11-18 0.1.0
2
45
  * Add binding for virConnectFindStoragePoolSources (clalance)
3
46
  * Fix dom_migrate (clalance)
data/README CHANGED
@@ -7,7 +7,7 @@ Usage
7
7
  -----
8
8
 
9
9
  In your ruby code, do a "require 'libvirt'"; to obtain a connection, use
10
- 'Libvirt::open' or 'Libvirt::openReadOnly'. See tests/*.rb for more
10
+ 'Libvirt::open' or 'Libvirt::open_read_only'. See tests/*.rb for more
11
11
  examples.
12
12
 
13
13
  Hacking
@@ -23,4 +23,42 @@ To run against the checkout, make sure you set RUBYLIB (assuming DIR is the
23
23
  toplevel of your source checkout):
24
24
 
25
25
  export RUBYLIB=$dir/lib:$dir/ext/libvirt
26
- ruby -rlibvirt -e 'puts Libvirt::version("xen")[0]'
26
+ ruby -rlibvirt -e 'puts Libvirt::version[0]'
27
+
28
+ Notes
29
+ -----
30
+ As of December 12, 2010, the ruby-libvirt bindings support all of the libvirt
31
+ APIs up to libvirt commit hash e8d05c978da774b7abbbc38dfcc00b9b582fdf72
32
+ with the following exceptions:
33
+
34
+ - virConnectRef
35
+ - virDomainGetConnect
36
+ - virDomainRef
37
+ - virDomainSetMemoryParameters
38
+ - virDomainGetMemoryParameters
39
+ - virDomainIsUpdated
40
+ - virDomainOpenConsole
41
+ - virNetworkGetConnect
42
+ - virNetworkRef
43
+ - virInterfaceGetConnect
44
+ - virInterfaceRef
45
+ - virStoragePoolGetConnect
46
+ - virStoragePoolRef
47
+ - virStorageVolGetConnect
48
+ - virStorageVolRef
49
+ - virNodeDeviceRef
50
+ - virSecretGetConnect
51
+ - virSecretRef
52
+ - virStreamNew
53
+ - virStreamRef
54
+ - virStreamSend
55
+ - virStreamRecv
56
+ - virStreamSendAll
57
+ - virStreamRecvAll
58
+ - virStreamEventAddCallback
59
+ - virStreamEventUpdateCallback
60
+ - virStreamEventRemoveCallback
61
+ - virStreamFinish
62
+ - virStreamAbort
63
+ - virStreamFree
64
+ - virNWFilterRef
@@ -5,6 +5,8 @@ The module Libvirt provides bindings to libvirt[http://libvirt.org]
5
5
  The various *Ptr types in Libvirt map loosely to the following Ruby classes:
6
6
 
7
7
  [virConnectPtr] Libvirt::Connect
8
+ [virNodeInfoPtr] Libvirt::Connect::Nodeinfo
9
+ [virSecurityModelPtr] Libvirt::Connect::NodeSecurityModel
8
10
  [virDomainPtr] Libvirt::Domain
9
11
  [virDomainInfoPtr] Libvirt::Domain::Info
10
12
  [virDomainInterfaceStatsPtr] Libvirt::Domain::InterfaceInfo
@@ -13,6 +15,7 @@ The various *Ptr types in Libvirt map loosely to the following Ruby classes:
13
15
  [virDomainMemoryStatPtr] Libvirt::Domain::MemoryStats
14
16
  [virDomainBlockInfoPtr] Libvirt::Domain::BlockInfo
15
17
  [virDomainSnapshotPtr] Libvirt::Domain::Snapshot
18
+ [virDomainJobInfoPtr] Libvirt::Domain::JobInfo
16
19
  [virNetworkPtr] Libvirt::Network
17
20
  [virNWFilterPtr] Libvirt::NWFilter
18
21
  [virNodeDevicePtr] Libvirt::NodeDevice
@@ -20,6 +23,5 @@ The various *Ptr types in Libvirt map loosely to the following Ruby classes:
20
23
  [virStoragePoolInfoPtr] Libvirt::StoragePoolInfo
21
24
  [virStorageVolPtr] Libvirt::StorageVol
22
25
  [virStorageVolInfoPtr] Libvirt::StorageVolInfo
23
- [virNodeInfoPtr] Libvirt::Nodeinfo
24
26
  [virSecretPtr] Libvirt::Secret
25
27
  [virInterfacePtr] Libvirt::Interface
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ require 'rake/testtask'
15
15
  require 'rake/gempackagetask'
16
16
 
17
17
  PKG_NAME='ruby-libvirt'
18
- PKG_VERSION='0.2.0'
18
+ PKG_VERSION='0.3.0'
19
19
 
20
20
  EXT_CONF='ext/libvirt/extconf.rb'
21
21
  MAKEFILE="ext/libvirt/Makefile"
@@ -31,14 +31,12 @@ LIBVIRT_SRC << MAKEFILE
31
31
  CLEAN.include [ "ext/**/*.o", LIBVIRT_MODULE,
32
32
  "ext/**/depend" ]
33
33
 
34
- CLOBBER.include [ "config.save", "ext/**/mkmf.log",
34
+ CLOBBER.include [ "config.save", "ext/**/mkmf.log", "ext/**/extconf.h",
35
35
  MAKEFILE ]
36
36
 
37
37
  #
38
38
  # Build locally
39
39
  #
40
- # FIXME: We can't get rid of install.rb yet, since there's no way
41
- # to pass config options to extconf.rb
42
40
  file MAKEFILE => EXT_CONF do |t|
43
41
  Dir::chdir(File::dirname(EXT_CONF)) do
44
42
  unless sh "ruby #{File::basename(EXT_CONF)}"
@@ -59,7 +57,7 @@ desc "Build the native library"
59
57
  task :build => LIBVIRT_MODULE
60
58
 
61
59
  Rake::TestTask.new(:test) do |t|
62
- t.test_files = FileList['tests/tc_*.rb']
60
+ t.test_files = [ 'tests/test_conn.rb', 'tests/test_domain.rb', 'tests/test_interface.rb', 'tests/test_network.rb', 'tests/test_nodedevice.rb', 'tests/test_nwfilter.rb', 'tests/test_open.rb', 'tests/test_secret.rb', 'tests/test_storage.rb' ]
63
61
  t.libs = [ 'lib', 'ext/libvirt' ]
64
62
  end
65
63
  task :test => :build
@@ -107,14 +105,6 @@ Rake::GemPackageTask.new(SPEC) do |pkg|
107
105
  pkg.need_zip = true
108
106
  end
109
107
 
110
- desc "Update the ruby-libvirt site"
111
- task :site => [ :rdoc ] do |t|
112
- system("rsync -av doc/site/ libvirt:/data/www/libvirt.org/ruby/")
113
- if $? != 0
114
- raise "rsync failed: #{$?}"
115
- end
116
- end
117
-
118
108
  desc "Build (S)RPM for #{PKG_NAME}"
119
109
  task :rpm => [ :package ] do |t|
120
110
  system("sed -e 's/@VERSION@/#{PKG_VERSION}/' #{SPEC_FILE} > pkg/#{SPEC_FILE}")
@@ -126,15 +116,3 @@ task :rpm => [ :package ] do |t|
126
116
  end
127
117
  end
128
118
  end
129
-
130
- desc "Release a version to the site"
131
- task :dist => [ :rpm ] do |t|
132
- puts "Copying files"
133
- unless sh "scp -p #{DIST_FILES.to_s} libvirt:/data/www/libvirt.org/ruby/download"
134
- $stderr.puts "Copy to libvirt failed"
135
- break
136
- end
137
- puts "Commit and tag #{PKG_VERSION}"
138
- system "hg commit -m 'Released version #{PKG_VERSION}'"
139
- system "hg tag -m 'Tag release #{PKG_VERSION}' #{PKG_NAME}-#{PKG_VERSION}"
140
- end
@@ -38,22 +38,26 @@ static VALUE c_libvirt_version;
38
38
 
39
39
  VALUE m_libvirt;
40
40
 
41
- // define additional errors here
42
- static VALUE e_ConnectionError; // ConnectionError - error durring connection establishment
41
+ /* define additional errors here */
42
+ static VALUE e_ConnectionError; /* ConnectionError - error during connection establishment */
43
43
  VALUE e_DefinitionError;
44
44
  VALUE e_RetrieveError;
45
45
  VALUE e_Error;
46
+ VALUE e_NoSupportError;
47
+
48
+ /* custom error function to suppress libvirt printing to stderr */
49
+ static void rubyLibvirtErrorFunc(void *userdata, virErrorPtr err){
50
+ }
46
51
 
47
52
  /*
48
53
  * call-seq:
49
- * Libvirt::version(type) -> [ libvirt_version, type_version ]
54
+ * Libvirt::version(type=nil) -> [ libvirt_version, type_version ]
50
55
  *
51
56
  * Call
52
57
  * +virGetVersion+[http://www.libvirt.org/html/libvirt-libvirt.html#virGetVersion]
53
- * to get the version of libvirt and of the hypervisor TYPE. Returns an
54
- * array with two entries of type Libvirt::Version.
58
+ * to get the version of libvirt and of the hypervisor TYPE.
55
59
  */
56
- VALUE libvirt_version(int argc, VALUE *argv, VALUE m) {
60
+ static VALUE libvirt_version(int argc, VALUE *argv, VALUE m) {
57
61
  unsigned long libVer;
58
62
  VALUE type;
59
63
  unsigned long typeVer;
@@ -63,8 +67,7 @@ VALUE libvirt_version(int argc, VALUE *argv, VALUE m) {
63
67
  rb_scan_args(argc, argv, "01", &type);
64
68
 
65
69
  r = virGetVersion(&libVer, get_string_or_nil(type), &typeVer);
66
- _E(r < 0, create_error(rb_eArgError, "virGetVersion",
67
- "Failed to get version", NULL));
70
+ _E(r < 0, create_error(rb_eArgError, "virGetVersion", NULL));
68
71
 
69
72
  result = rb_ary_new2(2);
70
73
  rargv[0] = rb_str_new2("libvirt");
@@ -91,47 +94,625 @@ static VALUE internal_open(int argc, VALUE *argv, VALUE m, int readonly)
91
94
  else
92
95
  conn = virConnectOpen(uri_c);
93
96
 
94
- if (conn == NULL)
95
- rb_raise(e_ConnectionError, "Failed to open%sconnection to '%s'", readonly ? " readonly " : " ", uri_c);
97
+ _E(conn == NULL, create_error(e_ConnectionError,
98
+ readonly ? "virConnectOpenReadOnly" : "virConnectOpen",
99
+ NULL));
96
100
 
97
101
  return connect_new(conn);
98
102
  }
99
103
 
100
104
  /*
101
105
  * call-seq:
102
- * Libvirt::open(url) -> Libvirt::Connect
106
+ * Libvirt::open(uri=nil) -> Libvirt::Connect
103
107
  *
104
108
  * Call
105
109
  * +virConnectOpen+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpen]
106
- * to open a connection to a URL. Returns a new Libvirt::Connect object.
110
+ * to open a connection to a URL.
107
111
  */
108
- VALUE libvirt_open(int argc, VALUE *argv, VALUE m) {
112
+ static VALUE libvirt_open(int argc, VALUE *argv, VALUE m) {
109
113
  return internal_open(argc, argv, m, 0);
110
114
  }
111
115
 
112
116
  /*
113
117
  * call-seq:
114
- * Libvirt::openReadOnly(url) -> Libvirt::Connect
118
+ * Libvirt::open_read_only(uri=nil) -> Libvirt::Connect
115
119
  *
116
120
  * Call
117
121
  * +virConnectOpenReadOnly+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpenReadOnly]
118
- * to open a read-only connection to a URL. Returns a new Libvirt::Connect
119
- * object.
122
+ * to open a read-only connection to a URL.
120
123
  */
121
- VALUE libvirt_open_read_only(int argc, VALUE *argv, VALUE m) {
124
+ static VALUE libvirt_open_read_only(int argc, VALUE *argv, VALUE m) {
122
125
  return internal_open(argc, argv, m, 1);
123
126
  }
124
127
 
128
+ #if HAVE_VIRCONNECTOPENAUTH
129
+ static int libvirt_auth_callback_wrapper(virConnectCredentialPtr cred,
130
+ unsigned int ncred, void *cbdata) {
131
+ VALUE userdata;
132
+ VALUE newcred;
133
+ int i;
134
+ VALUE result;
135
+
136
+ userdata = (VALUE)cbdata;
137
+
138
+ if (!rb_block_given_p())
139
+ rb_raise(rb_eRuntimeError, "No block given, this should never happen!\n");
140
+
141
+ for (i = 0; i < ncred; i++) {
142
+ newcred = rb_hash_new();
143
+
144
+ rb_hash_aset(newcred, rb_str_new2("type"), INT2FIX(cred[i].type));
145
+ rb_hash_aset(newcred, rb_str_new2("prompt"),
146
+ rb_str_new2(cred[i].prompt));
147
+ if (cred[i].challenge)
148
+ rb_hash_aset(newcred, rb_str_new2("challenge"),
149
+ rb_str_new2(cred[i].challenge));
150
+ else
151
+ rb_hash_aset(newcred, rb_str_new2("challenge"), Qnil);
152
+ if (cred[i].defresult)
153
+ rb_hash_aset(newcred, rb_str_new2("defresult"),
154
+ rb_str_new2(cred[i].defresult));
155
+ else
156
+ rb_hash_aset(newcred, rb_str_new2("defresult"), Qnil);
157
+ rb_hash_aset(newcred, rb_str_new2("result"), Qnil);
158
+ rb_hash_aset(newcred, rb_str_new2("userdata"), userdata);
159
+
160
+ result = rb_yield(newcred);
161
+ if (NIL_P(result)) {
162
+ cred[i].result = NULL;
163
+ cred[i].resultlen = 0;
164
+ }
165
+ else {
166
+ cred[i].result = strdup(StringValueCStr(result));
167
+ cred[i].resultlen = strlen(cred[i].result);
168
+ }
169
+ }
170
+
171
+ return 0;
172
+ }
173
+
174
+
175
+ struct wrap_callout {
176
+ char *uri;
177
+ virConnectAuthPtr auth;
178
+ unsigned int flags;
179
+ };
180
+
181
+ static VALUE rb_open_auth_wrap(VALUE arg) {
182
+ struct wrap_callout *e = (struct wrap_callout *)arg;
183
+
184
+ return (VALUE)virConnectOpenAuth(e->uri, e->auth, e->flags);
185
+ }
186
+
187
+ static VALUE rb_num2int_wrap(VALUE arg) {
188
+ return NUM2INT(arg);
189
+ }
190
+
191
+ /*
192
+ * call-seq:
193
+ * Libvirt::open_auth(uri=nil, credlist=nil, userdata=nil, flags=0) {|...| authentication block} -> Libvirt::Connect
194
+ *
195
+ * Call
196
+ * +virConnectOpenAuth+[http://www.libvirt.org/html/libvirt-libvirt.html#virConnectOpenAuth]
197
+ * to open a connection to a libvirt URI, with a possible authentication block.
198
+ * If an authentication block is desired, then credlist should be an array that
199
+ * specifies which credentials the authentication block is willing to support;
200
+ * the full list is available at http://libvirt.org/html/libvirt-libvirt.html#virConnectCredentialType.
201
+ * If userdata is not nil and an authentication block is given, userdata will
202
+ * be passed unaltered into the authentication block. The flags parameter
203
+ * controls how to open connection. The only options currently available for
204
+ * flags are 0 for a read/write connection and Libvirt::CONNECT_RO for a
205
+ * read-only connection.
206
+ *
207
+ * If the credlist is not empty, and an authentication block is given, the
208
+ * authentication block will be called once for each credential necessary
209
+ * to complete the authentication. The authentication block will be passed a
210
+ * single parameter, which is a hash of values containing information necessary
211
+ * to complete authentication. This hash contains 5 elements:
212
+ *
213
+ * type - the type of credential to be examined
214
+ *
215
+ * prompt - a suggested prompt to show to the user
216
+ *
217
+ * challenge - any additional challenge information
218
+ *
219
+ * defresult - a default result to use if credentials could not be obtained
220
+ *
221
+ * userdata - the userdata passed into open_auth initially
222
+ *
223
+ * The authentication block should return the result of collecting the
224
+ * information; these results will then be sent to libvirt for authentication.
225
+ */
226
+ static VALUE libvirt_open_auth(int argc, VALUE *argv, VALUE m) {
227
+ virConnectAuthPtr auth;
228
+ VALUE uri;
229
+ VALUE credlist;
230
+ VALUE userdata;
231
+ VALUE flags_val;
232
+ char *uri_c;
233
+ virConnectPtr conn = NULL;
234
+ unsigned int flags;
235
+ int auth_alloc;
236
+ int i;
237
+ VALUE tmp;
238
+ int exception = 0;
239
+ struct rb_ary_entry_arg args;
240
+ struct wrap_callout callargs;
241
+
242
+ rb_scan_args(argc, argv, "04", &uri, &credlist, &userdata, &flags_val);
243
+
244
+ /* handle the optional URI */
245
+ uri_c = get_string_or_nil(uri);
246
+
247
+ /* handle the optional flags */
248
+ if (NIL_P(flags_val))
249
+ flags = 0;
250
+ else
251
+ flags = NUM2UINT(flags_val);
252
+
253
+ if (rb_block_given_p()) {
254
+ auth = ALLOC(virConnectAuth);
255
+ auth_alloc = 1;
256
+
257
+ if (TYPE(credlist) == T_NIL)
258
+ auth->ncredtype = 0;
259
+ else if (TYPE(credlist) == T_ARRAY)
260
+ auth->ncredtype = RARRAY_LEN(credlist);
261
+ else
262
+ rb_raise(rb_eTypeError, "wrong argument type (expected Array or nil)");
263
+ auth->credtype = NULL;
264
+ if (auth->ncredtype > 0) {
265
+ /* we don't use ALLOC_N here because that can throw an exception,
266
+ * and leak the auth pointer. Instead we use normal malloc
267
+ * (which has a slightly higher chance of returning NULL), and
268
+ * then properly cleanup if it fails
269
+ */
270
+ auth->credtype = malloc(sizeof(int) * auth->ncredtype);
271
+ if (auth->credtype == NULL) {
272
+ xfree(auth);
273
+ rb_memerror();
274
+ }
275
+ for (i = 0; i < auth->ncredtype; i++) {
276
+ args.arr = credlist;
277
+ args.elem = i;
278
+ tmp = rb_protect(rb_ary_entry_wrap, (VALUE)&args, &exception);
279
+ if (exception)
280
+ goto do_cleanup;
281
+
282
+ auth->credtype[i] = rb_protect(rb_num2int_wrap, tmp,
283
+ &exception);
284
+ if (exception)
285
+ goto do_cleanup;
286
+ }
287
+ }
288
+
289
+ auth->cb = libvirt_auth_callback_wrapper;
290
+ auth->cbdata = (void *)userdata;
291
+ }
292
+ else {
293
+ auth = virConnectAuthPtrDefault;
294
+ auth_alloc = 0;
295
+ }
296
+
297
+ callargs.uri = uri_c;
298
+ callargs.auth = auth;
299
+ callargs.flags = flags;
300
+
301
+ conn = (virConnectPtr)rb_protect(rb_open_auth_wrap, (VALUE)&callargs,
302
+ &exception);
303
+
304
+ do_cleanup:
305
+ if (auth_alloc) {
306
+ free(auth->credtype);
307
+ xfree(auth);
308
+ }
309
+
310
+ if (exception)
311
+ rb_jump_tag(exception);
312
+
313
+ _E(conn == NULL, create_error(e_ConnectionError, "virConnectOpenAuth",
314
+ NULL));
315
+
316
+ return connect_new(conn);
317
+ }
318
+ #endif
319
+
320
+ #if HAVE_VIREVENTREGISTERIMPL
321
+ static VALUE add_handle, update_handle, remove_handle;
322
+ static VALUE add_timeout, update_timeout, remove_timeout;
323
+
324
+ /*
325
+ * call-seq:
326
+ * Libvirt::event_invoke_handle_callback(handle, fd, events, opaque) -> Qnil
327
+ *
328
+ * Unlike most of the other functions in the ruby-libvirt bindings, this one
329
+ * does not directly correspond to a libvirt API function. Instead, this
330
+ * module method (and event_invoke_timeout_callback) are meant to be called
331
+ * when there is an event of interest to libvirt on one of the file descriptors
332
+ * that libvirt uses. The application is notified of the file descriptors
333
+ * that libvirt uses via the callbacks from Libvirt::event_register_impl. When
334
+ * there is an event of interest, the application must call
335
+ * event_invoke_timeout_callback to ensure proper operation.
336
+ *
337
+ * Libvirt::event_invoke_handle_callback takes 4 arguments:
338
+ *
339
+ * handle
340
+ * an application specific handle ID. This can be any integer, but
341
+ * must be unique from all other libvirt handles in the application.
342
+ * fd
343
+ * the file descriptor of interest. This was given to the application
344
+ * as a callback to add_handle of Libvirt::event_register_impl
345
+ * events
346
+ * the events that have occured on the fd. Note that the events are
347
+ * libvirt specific, and are some combination of
348
+ * Libvirt::EVENT_HANDLE_READABLE, Libvirt::EVENT_HANDLE_WRITABLE,
349
+ * Libvirt::EVENT_HANDLE_ERROR, Libvirt::EVENT_HANDLE_HANGUP. To
350
+ * notify libvirt of more than one event at a time, these values should
351
+ * be logically OR'ed together.
352
+ * opaque
353
+ * the opaque data passed from libvirt during the
354
+ * Libvirt::event_register_impl add_handle callback. To ensure proper
355
+ * operation this data must be passed through to
356
+ * event_invoke_handle_callback without modification.
357
+ */
358
+ static VALUE libvirt_event_invoke_handle_callback(VALUE m, VALUE handle,
359
+ VALUE fd, VALUE events,
360
+ VALUE opaque) {
361
+ virEventHandleCallback cb;
362
+ void *op;
363
+ VALUE libvirt_cb;
364
+ VALUE libvirt_opaque;
365
+
366
+ if (TYPE(opaque) != T_HASH)
367
+ rb_raise(rb_eTypeError,
368
+ "wrong event callback argument type (expected Hash)");
369
+
370
+ libvirt_cb = rb_hash_aref(opaque, rb_str_new2("libvirt_cb"));
371
+
372
+ /* This is equivalent to Data_Get_Struct; I reproduce it here because
373
+ * I don't want the additional type-cast that Data_Get_Struct does
374
+ */
375
+ Check_Type(libvirt_cb, T_DATA);
376
+ cb = DATA_PTR(libvirt_cb);
377
+
378
+ if (cb) {
379
+ libvirt_opaque = rb_hash_aref(opaque, rb_str_new2("opaque"));
380
+ Data_Get_Struct(libvirt_opaque, void *, op);
381
+ cb(NUM2INT(handle), NUM2INT(fd), NUM2INT(events), op);
382
+ }
383
+
384
+ return Qnil;
385
+ }
386
+
387
+ /*
388
+ * call-seq:
389
+ * Libvirt::event_invoke_timeout_callback(timer, opaque) -> Qnil
390
+ *
391
+ * Unlike most of the other functions in the ruby-libvirt bindings, this one
392
+ * does not directly correspond to a libvirt API function. Instead, this
393
+ * module method (and event_invoke_handle_callback) are meant to be called
394
+ * when there is a timeout of interest to libvirt. The application is
395
+ * notified of the timers that libvirt uses via the callbacks from
396
+ * Libvirt::event_register_impl. When a timeout expires, the application must
397
+ * call event_invoke_timeout_callback to ensure proper operation.
398
+ *
399
+ * Libvirt::event_invoke_timeout_callback takes 2 arguments:
400
+ *
401
+ * handle
402
+ * an application specific timer ID. This can be any integer, but
403
+ * must be unique from all other libvirt timers in the application.
404
+ * opaque
405
+ * the opaque data passed from libvirt during the
406
+ * Libvirt::event_register_impl add_handle callback. To ensure proper
407
+ * operation this data must be passed through to
408
+ * event_invoke_handle_callback without modification.
409
+ */
410
+ static VALUE libvirt_event_invoke_timeout_callback(VALUE m, VALUE timer,
411
+ VALUE opaque) {
412
+ virEventTimeoutCallback cb;
413
+ void *op;
414
+ VALUE libvirt_cb;
415
+ VALUE libvirt_opaque;
416
+
417
+ if (TYPE(opaque) != T_HASH)
418
+ rb_raise(rb_eTypeError,
419
+ "wrong event callback argument type (expected Hash)");
420
+
421
+ libvirt_cb = rb_hash_aref(opaque, rb_str_new2("libvirt_cb"));
422
+
423
+ /* This is equivalent to Data_Get_Struct; I reproduce it here because
424
+ * I don't want the additional type-cast that Data_Get_Struct does
425
+ */
426
+ Check_Type(libvirt_cb, T_DATA);
427
+ cb = DATA_PTR(libvirt_cb);
428
+
429
+ if (cb) {
430
+ libvirt_opaque = rb_hash_aref(opaque, rb_str_new2("opaque"));
431
+ Data_Get_Struct(libvirt_opaque, void *, op);
432
+ cb(NUM2INT(timer), op);
433
+ }
434
+
435
+ return Qnil;
436
+ }
437
+
438
+ static int internal_add_handle_func(int fd, int events,
439
+ virEventHandleCallback cb, void *opaque,
440
+ virFreeCallback ff) {
441
+ VALUE rubyargs;
442
+ VALUE res;
443
+
444
+ rubyargs = rb_hash_new();
445
+ rb_hash_aset(rubyargs, rb_str_new2("libvirt_cb"),
446
+ Data_Wrap_Struct(rb_class_of(add_handle), NULL, NULL, cb));
447
+ rb_hash_aset(rubyargs, rb_str_new2("opaque"),
448
+ Data_Wrap_Struct(rb_class_of(add_handle), NULL, NULL, opaque));
449
+ rb_hash_aset(rubyargs, rb_str_new2("free_func"),
450
+ Data_Wrap_Struct(rb_class_of(add_handle), NULL, NULL, ff));
451
+
452
+ /* call out to the ruby object */
453
+ if (strcmp(rb_obj_classname(add_handle), "Symbol") == 0)
454
+ res = rb_funcall(rb_class_of(add_handle), rb_to_id(add_handle), 3,
455
+ INT2FIX(fd), INT2FIX(events), rubyargs);
456
+ else if (strcmp(rb_obj_classname(add_handle), "Proc") == 0)
457
+ res = rb_funcall(add_handle, rb_intern("call"), 3, INT2FIX(fd),
458
+ INT2FIX(events), rubyargs);
459
+ else
460
+ rb_raise(rb_eTypeError,
461
+ "wrong add handle callback argument type (expected Symbol or Proc)");
462
+
463
+ if (TYPE(res) != T_FIXNUM)
464
+ rb_raise(rb_eTypeError,
465
+ "expected integer return from add_handle callback");
466
+
467
+ return NUM2INT(res);
468
+ }
469
+
470
+ static void internal_update_handle_func(int watch, int event) {
471
+ /* call out to the ruby object */
472
+ if (strcmp(rb_obj_classname(update_handle), "Symbol") == 0)
473
+ rb_funcall(rb_class_of(update_handle), rb_to_id(update_handle), 2,
474
+ INT2FIX(watch), INT2FIX(event));
475
+ else if (strcmp(rb_obj_classname(update_handle), "Proc") == 0)
476
+ rb_funcall(update_handle, rb_intern("call"), 2, INT2FIX(watch),
477
+ INT2FIX(event));
478
+ else
479
+ rb_raise(rb_eTypeError,
480
+ "wrong update handle callback argument type (expected Symbol or Proc)");
481
+ }
482
+
483
+ static int internal_remove_handle_func(int watch) {
484
+ VALUE res;
485
+ virFreeCallback ff_cb;
486
+ void *op;
487
+ VALUE libvirt_opaque;
488
+ VALUE ff;
489
+
490
+ /* call out to the ruby object */
491
+ if (strcmp(rb_obj_classname(remove_handle), "Symbol") == 0)
492
+ res = rb_funcall(rb_class_of(remove_handle), rb_to_id(remove_handle),
493
+ 1, INT2FIX(watch));
494
+ else if (strcmp(rb_obj_classname(remove_handle), "Proc") == 0)
495
+ res = rb_funcall(remove_handle, rb_intern("call"), 1, INT2FIX(watch));
496
+ else
497
+ rb_raise(rb_eTypeError,
498
+ "wrong remove handle callback argument type (expected Symbol or Proc)");
499
+
500
+ if (TYPE(res) != T_HASH)
501
+ rb_raise(rb_eTypeError,
502
+ "expected opaque hash returned from remove_handle callback");
503
+
504
+ ff = rb_hash_aref(res, rb_str_new2("free_func"));
505
+ if (!NIL_P(ff)) {
506
+ /* This is equivalent to Data_Get_Struct; I reproduce it here because
507
+ * I don't want the additional type-cast that Data_Get_Struct does
508
+ */
509
+ Check_Type(ff, T_DATA);
510
+ ff_cb = DATA_PTR(ff);
511
+ if (ff_cb) {
512
+ libvirt_opaque = rb_hash_aref(res, rb_str_new2("opaque"));
513
+ Data_Get_Struct(libvirt_opaque, void *, op);
514
+
515
+ (*ff_cb)(op);
516
+ }
517
+ }
518
+
519
+ return 0;
520
+ }
521
+
522
+ static int internal_add_timeout_func(int interval, virEventTimeoutCallback cb,
523
+ void *opaque, virFreeCallback ff) {
524
+ VALUE rubyargs;
525
+ VALUE res;
526
+
527
+ rubyargs = rb_hash_new();
528
+
529
+ rb_hash_aset(rubyargs, rb_str_new2("libvirt_cb"),
530
+ Data_Wrap_Struct(rb_class_of(add_timeout), NULL, NULL, cb));
531
+ rb_hash_aset(rubyargs, rb_str_new2("opaque"),
532
+ Data_Wrap_Struct(rb_class_of(add_timeout), NULL, NULL,
533
+ opaque));
534
+ rb_hash_aset(rubyargs, rb_str_new2("free_func"),
535
+ Data_Wrap_Struct(rb_class_of(add_timeout), NULL, NULL, ff));
536
+
537
+ /* call out to the ruby object */
538
+ if (strcmp(rb_obj_classname(add_timeout), "Symbol") == 0)
539
+ res = rb_funcall(rb_class_of(add_timeout), rb_to_id(add_timeout), 2,
540
+ INT2FIX(interval), rubyargs);
541
+ else if (strcmp(rb_obj_classname(add_timeout), "Proc") == 0)
542
+ res = rb_funcall(add_timeout, rb_intern("call"), 2, INT2FIX(interval),
543
+ rubyargs);
544
+ else
545
+ rb_raise(rb_eTypeError,
546
+ "wrong add timeout callback argument type (expected Symbol or Proc)");
547
+
548
+ if (TYPE(res) != T_FIXNUM)
549
+ rb_raise(rb_eTypeError,
550
+ "expected integer return from add_timeout callback");
551
+
552
+ return NUM2INT(res);
553
+ }
554
+
555
+ static void internal_update_timeout_func(int timer, int timeout) {
556
+ /* call out to the ruby object */
557
+ if (strcmp(rb_obj_classname(update_timeout), "Symbol") == 0)
558
+ rb_funcall(rb_class_of(update_timeout), rb_to_id(update_timeout), 2,
559
+ INT2FIX(timer), INT2FIX(timeout));
560
+ else if (strcmp(rb_obj_classname(update_timeout), "Proc") == 0)
561
+ rb_funcall(update_timeout, rb_intern("call"), 2, INT2FIX(timer),
562
+ INT2FIX(timeout));
563
+ else
564
+ rb_raise(rb_eTypeError,
565
+ "wrong update timeout callback argument type (expected Symbol or Proc)");
566
+ }
567
+
568
+ static int internal_remove_timeout_func(int timer) {
569
+ VALUE res;
570
+ virFreeCallback ff_cb;
571
+ void *op;
572
+ VALUE libvirt_opaque;
573
+ VALUE ff;
574
+
575
+ /* call out to the ruby object */
576
+ if (strcmp(rb_obj_classname(remove_timeout), "Symbol") == 0)
577
+ res = rb_funcall(rb_class_of(remove_timeout), rb_to_id(remove_timeout),
578
+ 1, INT2FIX(timer));
579
+ else if (strcmp(rb_obj_classname(remove_timeout), "Proc") == 0)
580
+ res = rb_funcall(remove_timeout, rb_intern("call"), 1, INT2FIX(timer));
581
+ else
582
+ rb_raise(rb_eTypeError,
583
+ "wrong remove timeout callback argument type (expected Symbol or Proc)");
584
+
585
+ if (TYPE(res) != T_HASH)
586
+ rb_raise(rb_eTypeError,
587
+ "expected opaque hash returned from remove_timeout callback");
588
+
589
+ ff = rb_hash_aref(res, rb_str_new2("free_func"));
590
+ if (!NIL_P(ff)) {
591
+ /* This is equivalent to Data_Get_Struct; I reproduce it here because
592
+ * I don't want the additional type-cast that Data_Get_Struct does
593
+ */
594
+ Check_Type(ff, T_DATA);
595
+ ff_cb = DATA_PTR(ff);
596
+ if (ff_cb) {
597
+ libvirt_opaque = rb_hash_aref(res, rb_str_new2("opaque"));
598
+ Data_Get_Struct(libvirt_opaque, void *, op);
599
+
600
+ (*ff_cb)(op);
601
+ }
602
+ }
603
+
604
+ return 0;
605
+ }
606
+
607
+ #define set_event_func_or_null(type) \
608
+ do { \
609
+ if (NIL_P(type)) \
610
+ type##_temp = NULL; \
611
+ else \
612
+ type##_temp = internal_##type##_func; \
613
+ } while(0)
614
+
615
+ static int is_symbol_proc_or_nil(VALUE handle) {
616
+ if (NIL_P(handle))
617
+ return 1;
618
+ return is_symbol_or_proc(handle);
619
+ }
620
+
621
+ /*
622
+ * call-seq:
623
+ * Libvirt::event_register_impl(add_handle=nil, update_handle=nil, remove_handle=nil, add_timeout=nil, update_timeout=nil, remove_timeout=nil) -> Qnil
624
+ *
625
+ * Call
626
+ * +virEventRegisterImpl+[http://www.libvirt.org/html/libvirt-libvirt.html#virEventRegisterImpl]
627
+ * to register callback handlers for handles and timeouts. These handles and
628
+ * timeouts are used as part of the libvirt infrastructure for generating
629
+ * domain events. Each callback must be a Symbol (that is the name of a
630
+ * method to callback), a Proc, or nil (to disable the callback). In the
631
+ * end-user application program, these callbacks are typically used to track
632
+ * the file descriptors or timers that libvirt is interested in (and is intended
633
+ * to be integrated into the "main loop" of a UI program). The individual
634
+ * callbacks will be given a certain number of arguments, and must return
635
+ * certain values. Those arguments and return types are:
636
+ *
637
+ * add_handle(fd, events, opaque) => Fixnum
638
+ *
639
+ * update_handle(handleID, event) => nil
640
+ *
641
+ * remove_handle(handleID) => opaque data from add_handle
642
+ *
643
+ * add_timeout(interval, opaque) => Fixnum
644
+ *
645
+ * update_timeout(timerID, timeout) => nil
646
+ *
647
+ * remove_timeout(timerID) => opaque data from add_timeout
648
+ *
649
+ * Any arguments marked as "opaque" must be accepted from the library and saved
650
+ * without modification. The values passed to the callbacks are meant to be
651
+ * passed to the event_invoke_handle_callback and event_invoke_timeout_callback
652
+ * module methods; see the documentation for those methods for more details.
653
+ */
654
+ static VALUE libvirt_conn_event_register_impl(int argc, VALUE *argv, VALUE c) {
655
+ virEventAddHandleFunc add_handle_temp;
656
+ virEventUpdateHandleFunc update_handle_temp;
657
+ virEventRemoveHandleFunc remove_handle_temp;
658
+ virEventAddTimeoutFunc add_timeout_temp;
659
+ virEventUpdateTimeoutFunc update_timeout_temp;
660
+ virEventRemoveTimeoutFunc remove_timeout_temp;
661
+
662
+ /*
663
+ * subtle; we put the arguments (callbacks) directly into the global
664
+ * add_handle, update_handle, etc. variables. Then we register the
665
+ * internal functions as the callbacks with virEventRegisterImpl
666
+ */
667
+ rb_scan_args(argc, argv, "06", &add_handle, &update_handle, &remove_handle,
668
+ &add_timeout, &update_timeout, &remove_timeout);
669
+
670
+ if (!is_symbol_proc_or_nil(add_handle) ||
671
+ !is_symbol_proc_or_nil(update_handle) ||
672
+ !is_symbol_proc_or_nil(remove_handle) ||
673
+ !is_symbol_proc_or_nil(add_timeout) ||
674
+ !is_symbol_proc_or_nil(update_timeout) ||
675
+ !is_symbol_proc_or_nil(remove_timeout))
676
+ rb_raise(rb_eTypeError,
677
+ "wrong argument type (expected Symbol, Proc, or nil)");
678
+
679
+ set_event_func_or_null(add_handle);
680
+ set_event_func_or_null(update_handle);
681
+ set_event_func_or_null(remove_handle);
682
+ set_event_func_or_null(add_timeout);
683
+ set_event_func_or_null(update_timeout);
684
+ set_event_func_or_null(remove_timeout);
685
+
686
+ /* virEventRegisterImpl returns void, so no error checking here */
687
+ virEventRegisterImpl(add_handle_temp, update_handle_temp,
688
+ remove_handle_temp, add_timeout_temp,
689
+ update_timeout_temp, remove_timeout_temp);
690
+
691
+ return Qnil;
692
+ }
693
+ #endif
694
+
125
695
  /*
126
696
  * Module Libvirt
127
697
  */
128
698
  void Init__libvirt() {
129
- int r;
130
-
131
699
  m_libvirt = rb_define_module("Libvirt");
132
700
  c_libvirt_version = rb_define_class_under(m_libvirt, "Version",
133
701
  rb_cObject);
134
702
 
703
+ #if HAVE_VIRCONNECTOPENAUTH
704
+ rb_define_const(m_libvirt, "CONNECT_RO", INT2NUM(VIR_CONNECT_RO));
705
+
706
+ rb_define_const(m_libvirt, "CRED_USERNAME", INT2NUM(VIR_CRED_USERNAME));
707
+ rb_define_const(m_libvirt, "CRED_AUTHNAME", INT2NUM(VIR_CRED_AUTHNAME));
708
+ rb_define_const(m_libvirt, "CRED_LANGUAGE", INT2NUM(VIR_CRED_LANGUAGE));
709
+ rb_define_const(m_libvirt, "CRED_CNONCE", INT2NUM(VIR_CRED_CNONCE));
710
+ rb_define_const(m_libvirt, "CRED_PASSPHRASE", INT2NUM(VIR_CRED_PASSPHRASE));
711
+ rb_define_const(m_libvirt, "CRED_ECHOPROMPT", INT2NUM(VIR_CRED_ECHOPROMPT));
712
+ rb_define_const(m_libvirt, "CRED_NOECHOPROMPT", INT2NUM(VIR_CRED_NOECHOPROMPT));
713
+ rb_define_const(m_libvirt, "CRED_REALM", INT2NUM(VIR_CRED_REALM));
714
+ rb_define_const(m_libvirt, "CRED_EXTERNAL", INT2NUM(VIR_CRED_EXTERNAL));
715
+ #endif
135
716
 
136
717
  /*
137
718
  * Libvirt Errors
@@ -144,17 +725,45 @@ void Init__libvirt() {
144
725
  e_Error);
145
726
  e_RetrieveError = rb_define_class_under(m_libvirt, "RetrieveError",
146
727
  e_Error);
728
+ e_NoSupportError = rb_define_class_under(m_libvirt, "NoSupportError",
729
+ e_Error);
147
730
 
148
- // create 'libvirt_function_name' and 'vir_connect_ptr' attributes on e_Error class
149
731
  rb_define_attr(e_Error, "libvirt_function_name", 1, 0);
150
732
  rb_define_attr(e_Error, "libvirt_message", 1, 0);
151
733
 
152
734
  rb_define_module_function(m_libvirt, "version", libvirt_version, -1);
153
- rb_define_module_function(m_libvirt, "open", libvirt_open, -1);
154
- rb_define_module_function(m_libvirt, "open_read_only",
735
+ rb_define_module_function(m_libvirt, "open", libvirt_open, -1);
736
+ rb_define_module_function(m_libvirt, "open_read_only",
155
737
  libvirt_open_read_only, -1);
156
- // FIXME: implement this
157
- //rb_define_module_function(m_libvirt, "open_auth", libvirt_open_auth, -1);
738
+ #if HAVE_VIRCONNECTOPENAUTH
739
+ rb_define_module_function(m_libvirt, "open_auth", libvirt_open_auth, -1);
740
+ #endif
741
+
742
+ #if HAVE_VIREVENTREGISTERIMPL
743
+ rb_define_const(m_libvirt, "EVENT_HANDLE_READABLE",
744
+ INT2NUM(VIR_EVENT_HANDLE_READABLE));
745
+ rb_define_const(m_libvirt, "EVENT_HANDLE_WRITABLE",
746
+ INT2NUM(VIR_EVENT_HANDLE_WRITABLE));
747
+ rb_define_const(m_libvirt, "EVENT_HANDLE_ERROR",
748
+ INT2NUM(VIR_EVENT_HANDLE_ERROR));
749
+ rb_define_const(m_libvirt, "EVENT_HANDLE_HANGUP",
750
+ INT2NUM(VIR_EVENT_HANDLE_HANGUP));
751
+
752
+ /* since we are using globals, we have to register with the gc */
753
+ rb_global_variable(&add_handle);
754
+ rb_global_variable(&update_handle);
755
+ rb_global_variable(&remove_handle);
756
+ rb_global_variable(&add_timeout);
757
+ rb_global_variable(&update_timeout);
758
+ rb_global_variable(&remove_timeout);
759
+
760
+ rb_define_module_function(m_libvirt, "event_register_impl",
761
+ libvirt_conn_event_register_impl, -1);
762
+ rb_define_module_function(m_libvirt, "event_invoke_handle_callback",
763
+ libvirt_event_invoke_handle_callback, 4);
764
+ rb_define_module_function(m_libvirt, "event_invoke_timeout_callback",
765
+ libvirt_event_invoke_timeout_callback, 2);
766
+ #endif
158
767
 
159
768
  init_connect();
160
769
  init_storage();
@@ -165,16 +774,8 @@ void Init__libvirt() {
165
774
  init_interface();
166
775
  init_domain();
167
776
 
168
- r = virInitialize();
169
- if (r < 0)
777
+ virSetErrorFunc(NULL, rubyLibvirtErrorFunc);
778
+
779
+ if (virInitialize() < 0)
170
780
  rb_raise(rb_eSystemCallError, "virInitialize failed");
171
781
  }
172
-
173
- /*
174
- * Local variables:
175
- * indent-tabs-mode: nil
176
- * c-indent-level: 4
177
- * c-basic-offset: 4
178
- * tab-width: 4
179
- * End:
180
- */