libvirt_async 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b24efe4c5438e07c1fbc9fac06b82493e242deb7
4
- data.tar.gz: c49f812826b3e2275065f52f587a29ef3dec95ae
2
+ SHA256:
3
+ metadata.gz: e2b8dda8105b9fe625c1d8bf71634ad66d1dca7507315c09e340eab1b9cfbde5
4
+ data.tar.gz: 5dc290b2014113e4ad84f3ed36dc4afbe177c95a1124948c2efd47a689062078
5
5
  SHA512:
6
- metadata.gz: cbb0387eabbed0bd926268e62e7995fead38c42e5ee7b01f663e24d03f41c165cf54c219d17102842d4d6a98d6ba18d0f0c91ea4f43b61b57fe31877c80e4af4
7
- data.tar.gz: deb1c6f89322e867a97da6b4d3e7e694b515b9f5e9c7edaced04865cf18b386ef946aafae8eaf502fd89ad84329449c79195dcfef06a90a248edcfb6942abdef
6
+ metadata.gz: 645fdff4cfe5c25e405ee02c49fa3c15c1a4ae6ad58922cd4ded7a14215ede30559480a6f2712d384d1268d49ff8eda4dd916ce2332d749a46a3f49d7c0907d3
7
+ data.tar.gz: 5cf5d9a3b65a5e019e420298f98d8acd2c6480b2eb9b29867a4c42e8111987ed67c7abeef27f4cbaa2786384da97ae746043c3a5c69c95651d844f6ae0995cdc
@@ -1,11 +1,13 @@
1
1
  # Changelog
2
2
 
3
3
  ## Unreleased
4
+ - Add StreamRead for working with non-block streams in read mode
5
+ - Improve README
4
6
 
5
7
  ## 0.1.1
6
- - fix async tasks hierarchy
8
+ - Fix async tasks hierarchy
7
9
 
8
10
  ## 0.1.0
9
11
 
10
- - register implementations
11
- - debug logging
12
+ - Register implementations
13
+ - Debug logging
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # LibvirtAsync
2
2
 
3
- Libvirt event async implementation.
4
- Libvirt event api implementation on Fibers based on [libvirt-ruby](https://github.com/qwe/libvirt-ruby) and [async](https://github.com/socketry/async)
3
+ Libvirt event loop asynchronous implementation on Fibers.
4
+ Based on [libvirt-ruby](https://github.com/qwe/libvirt-ruby) and [async](https://github.com/socketry/async).
5
+ Allows to receive domain events.
6
+ Allows to work with streams in asynchronous mode.
5
7
 
6
8
  ## Installation
7
9
 
@@ -21,21 +23,133 @@ Or install it yourself as:
21
23
 
22
24
  ## Usage
23
25
 
26
+ `LibvirtAsync.register_implementations!` must be called once per process before connecting to hypervisor.
27
+
28
+ ### Receiving domain events
29
+
30
+ We can subscribe for event from all hypervisor's domains
24
31
  ```ruby
25
32
  require 'libvirt_async'
26
33
 
27
- LibvirtAsync.use_logger!
28
- LibvirtAsync.logger.level = Logger::Severity::DEBUG # optional for debugging
29
34
  LibvirtAsync.register_implementations!
35
+
36
+ connection = Libvirt::open('qemu+tcp://127.0.0.1:16509')
37
+
38
+ some_object = Object.new
39
+
40
+ connection.domain_event_register_any(
41
+ Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE,
42
+ ->(connection, domain, event, detail, opaque) {
43
+ puts "LIFECYCLE event #{domain.uuid} #{event} #{detail}"
44
+ },
45
+ nil, # optional domain, can be omitted
46
+ some_object # will be an opaque in callback, can be omitted
47
+ )
30
48
  ```
31
49
 
32
- ## Development
50
+ Or we can subscribe on particular domain
51
+
52
+ ```ruby
53
+ require 'libvirt_async'
54
+
55
+ LibvirtAsync.register_implementations!
56
+
57
+ connection = Libvirt::open('qemu+tcp://127.0.0.1:16509')
58
+ domain = connection.list_all_domains.first
33
59
 
34
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
35
- You can also run `bin/console` for an interactive prompt that will allow you to experiment.
60
+ some_object = Object.new
61
+
62
+ connection.domain_event_register_any(
63
+ Libvirt::Connect::DOMAIN_EVENT_ID_LIFECYCLE,
64
+ ->(connection, domain, event, detail, opaque) {
65
+ puts "LIFECYCLE event #{domain.uuid} #{event} #{detail}"
66
+ },
67
+ domain,
68
+ some_object # will be an opaque in callback, can be omitted
69
+ )
70
+ ```
71
+
72
+ All available domain events:
73
+ ```ruby
74
+ connection.domain_event_register_any(
75
+ Libvirt::Connect::DOMAIN_EVENT_ID_REBOOT,
76
+ ->(connection, domain, opaque) {
77
+ puts "REBOOT event #{domain.uuid}"
78
+ }
79
+ )
80
+
81
+ connection.domain_event_register_any(
82
+ Libvirt::Connect::DOMAIN_EVENT_ID_RTC_CHANGE,
83
+ ->(connection, domain, utc_offset, opaque) {
84
+ puts "RTC_CHANGE event #{domain.uuid} #{utc_offset}"
85
+ }
86
+ )
87
+
88
+ connection.domain_event_register_any(
89
+ Libvirt::Connect::DOMAIN_EVENT_ID_WATCHDOG,
90
+ ->(connection, domain, action, opaque) {
91
+ puts "WATCHDOG event #{domain.uuid} #{action}"
92
+ }
93
+ )
94
+
95
+ connection.domain_event_register_any(
96
+ Libvirt::Connect::DOMAIN_EVENT_ID_IO_ERROR,
97
+ ->(connection, domain, src_path, dev_alias, action, opaque) {
98
+ puts "IO_ERROR event #{domain.uuid} #{src_path} #{dev_alias} #{action}"
99
+ }
100
+ )
101
+
102
+ connection.domain_event_register_any(
103
+ Libvirt::Connect::DOMAIN_EVENT_ID_IO_ERROR_REASON,
104
+ ->(connection, domain, src_path, dev_alias, action, opaque) {
105
+ puts "IO_ERROR_REASON event #{domain.uuid} #{src_path} #{dev_alias} #{action}"
106
+ }
107
+ )
108
+
109
+ connection.domain_event_register_any(
110
+ Libvirt::Connect::DOMAIN_EVENT_ID_GRAPHICS,
111
+ ->(connection, domain, phase, local, remote, auth_scheme, subject, opaque) {
112
+ puts "GRAPHICS event #{domain.uuid} #{phase} #{local} #{remote} #{auth_scheme} #{subject}"
113
+ }
114
+ )
115
+ ```
116
+
117
+ ### Taking screenshot
118
+
119
+ ```ruby
120
+ require 'libvirt_async'
121
+
122
+ LibvirtAsync.register_implementations!
123
+
124
+ connection = Libvirt::open('qemu+tcp://127.0.0.1:16509')
125
+ domain = connection.list_all_domains.first
126
+
127
+ file = File.new("/screenshots/#{domain.uuid}.pnm", 'wb')
128
+ stream = LibvirtAsync::StreamRead.new(connection, file)
129
+ mime_type = domain.screenshot(stream.stream, 0)
130
+ puts "screenshot saving initiated mime_type=#{mime_type}"
131
+
132
+ # will start screenshot saving
133
+ stream.call do |success, reason, io|
134
+ # this block will be called asynchronously on complete or error
135
+ io.close
136
+ if success
137
+ puts "screenshot saved at #{io.path}"
138
+ else
139
+ puts "screenshot was not saved: #{reason}"
140
+ end
141
+ end
142
+ ```
143
+
144
+ Logging.
145
+ ```ruby
146
+ require 'libvirt_async'
147
+
148
+ LibvirtAsync.use_logger!
149
+ LibvirtAsync.logger.level = Logger::Severity::DEBUG # for debugging
150
+ ```
36
151
 
37
- To install this gem onto your local machine, run `bundle exec rake install`.
38
- To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
152
+ Look at [ruby-libvirt Documenation](https://libvirt.org/ruby/documentation.html) for further details.
39
153
 
40
154
  ## Contributing
41
155
 
@@ -2,6 +2,7 @@ require 'libvirt_async/version'
2
2
  require 'libvirt_async/error'
3
3
  require 'libvirt_async/log_formatter'
4
4
  require 'libvirt_async/implementations'
5
+ require 'libvirt_async/stream_read'
5
6
 
6
7
  module LibvirtAsync
7
8
  def register_implementations!
@@ -0,0 +1,144 @@
1
+ module LibvirtAsync
2
+ class StreamRead
3
+ # StreamRead allows to work with stream in non-block read mode.
4
+
5
+ STATE_COMPLETED = 'completed'.freeze
6
+ STATE_CANCELLED = 'cancelled'.freeze
7
+ STATE_FAILED = 'failed'.freeze
8
+ STATE_PENDING = 'pending'.freeze
9
+
10
+ class RecvError < StandardError
11
+ end
12
+
13
+ include WithDbg
14
+
15
+ attr_reader :state, :stream, :io
16
+
17
+ # @param connection [Libvirt::Connection]
18
+ # @param io [IO]
19
+ # @return [LibvirtAsync::Stream]
20
+ def initialize(connection, io)
21
+ @connection = connection
22
+ @io = io
23
+ @callback = nil
24
+ @state = STATE_PENDING
25
+ @stream = @connection.stream(Libvirt::Stream::NONBLOCK)
26
+ end
27
+
28
+ # @yield asynchronously on complete or error
29
+ # @yieldparam success [Boolean]
30
+ # @yieldparam reason [String,NilClass]
31
+ # @yieldparam io [IO]
32
+ def call(&block)
33
+ add_callback(block) if block_given?
34
+
35
+ run
36
+ end
37
+
38
+ def add_callback(block)
39
+ raise ArgumentError, 'block must be a Proc' unless @callback.is_a?(Proc)
40
+ @callback = block
41
+ end
42
+
43
+ def run
44
+ raise ArgumentError, 'block must be given' if @callback.nil?
45
+
46
+ dbg { "#{to_s}#call event_add_callback calling" }
47
+ @cb_opaque = stream.event_add_callback(
48
+ Libvirt::Stream::EVENT_READABLE,
49
+ -> (_stream, events, _opaque) { stream_callback(events) },
50
+ self
51
+ )
52
+ dbg { "#{to_s}#call event_add_callback called" }
53
+
54
+ nil
55
+ rescue Libvirt::Error => e
56
+ dbg { "#{to_s}#call error occurred\n<#{e.class}>: #{e.message}\n#{e.backtrace.join("\n")}" }
57
+ @state = STATE_FAILED
58
+ stream&.finish rescue nil
59
+ on_error(e)
60
+ @cb_opaque = nil
61
+ end
62
+
63
+ def cancel
64
+ dbg { "#{to_s}#cancel" }
65
+ return if stream.nil?
66
+
67
+ @state = STATE_CANCELLED
68
+ stream.event_remove_callback
69
+ stream.finish
70
+ @stream = nil
71
+ rescue Libvirt::Error => e
72
+ dbg { "#{to_s}#cancel error occurred\n<#{e.class}>: #{e.message}\n#{e.backtrace.join("\n")}" }
73
+ @stream = nil
74
+ ensure
75
+ @cb_opaque = nil
76
+ end
77
+
78
+ def to_s
79
+ "#<#{self.class}:0x#{object_id.to_s(16)} @state=#{@state}>"
80
+ end
81
+
82
+ def inspect
83
+ to_s
84
+ end
85
+
86
+ private
87
+
88
+ def on_error(error)
89
+ @callback.call(false, "#{error.class}: #{error.message}", io)
90
+ end
91
+
92
+ def on_receive(data)
93
+ io.write(data)
94
+ end
95
+
96
+ def on_complete
97
+ @callback.call(true, nil, io)
98
+ end
99
+
100
+ # @param events [Integer]
101
+ def stream_callback(events)
102
+ dbg { "#{to_s}#stream_callback events=#{events}" }
103
+ return unless (Libvirt::Stream::EVENT_READABLE & events) != 0
104
+ # `stream.finish` will be executed asynchronously
105
+ # so callback will be triggered even after we complete data transfer.
106
+ if state != STATE_PENDING
107
+ dbg { "#{to_s}#stream_callback called for #{state} stream. Skipping." }
108
+ return
109
+ end
110
+
111
+ process_read
112
+
113
+ rescue RecvError, Libvirt::Error => e
114
+ dbg { "#{to_s}#stream_callback error occurred\n<#{e.class}>: #{e.message}\n#{e.backtrace.join("\n")}" }
115
+ @state = STATE_FAILED
116
+ stream.finish rescue nil
117
+ on_error(e)
118
+ @cb_opaque = nil
119
+ end
120
+
121
+ def process_read
122
+ code, data = stream.recv(1024)
123
+ dbg { "#{to_s}#stream_callback recv code=#{code}, size=#{data&.size}" }
124
+
125
+ case code
126
+ when 0
127
+ dbg { "#{to_s}#stream_callback finished" }
128
+ @state = STATE_COMPLETED
129
+ stream.finish
130
+ on_complete
131
+ @cb_opaque = nil
132
+ when -1
133
+ dbg { "#{to_s}#stream_callback code -1" }
134
+ raise RecvError, 'error code -1 received'
135
+ when -2
136
+ dbg { "#{to_s}#stream_callback is not ready" }
137
+ else
138
+ dbg { "#{to_s}#stream_callback ready code=#{code}" }
139
+ on_receive(data)
140
+ end
141
+ end
142
+
143
+ end
144
+ end
@@ -1,3 +1,3 @@
1
1
  module LibvirtAsync
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libvirt_async
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Talakevich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-29 00:00:00.000000000 Z
11
+ date: 2020-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-libvirt
@@ -75,6 +75,7 @@ files:
75
75
  - lib/libvirt_async/handle.rb
76
76
  - lib/libvirt_async/implementations.rb
77
77
  - lib/libvirt_async/log_formatter.rb
78
+ - lib/libvirt_async/stream_read.rb
78
79
  - lib/libvirt_async/timer.rb
79
80
  - lib/libvirt_async/util.rb
80
81
  - lib/libvirt_async/version.rb
@@ -102,8 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
103
  - !ruby/object:Gem::Version
103
104
  version: '0'
104
105
  requirements: []
105
- rubyforge_project:
106
- rubygems_version: 2.4.8
106
+ rubygems_version: 3.0.6
107
107
  signing_key:
108
108
  specification_version: 4
109
109
  summary: Libvirt event async implementation.