ruby-libvirt 0.2.0 → 0.3.0

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