hrr_rb_netconf 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +8 -1
- data/hrr_rb_netconf.gemspec +3 -1
- data/lib/hrr_rb_netconf/server/capability/base_1_0.rb +1 -1
- data/lib/hrr_rb_netconf/server/capability/confirmed_commit_1_0.rb +0 -7
- data/lib/hrr_rb_netconf/server/capability/notification_1_0.rb +81 -0
- data/lib/hrr_rb_netconf/server/capability/validate_1_0.rb +0 -1
- data/lib/hrr_rb_netconf/server/capability.rb +1 -0
- data/lib/hrr_rb_netconf/server/notification_event.rb +47 -0
- data/lib/hrr_rb_netconf/server/notification_stream.rb +27 -0
- data/lib/hrr_rb_netconf/server/notification_streams.rb +40 -0
- data/lib/hrr_rb_netconf/server/session.rb +179 -35
- data/lib/hrr_rb_netconf/server.rb +34 -6
- data/lib/hrr_rb_netconf/version.rb +1 -1
- metadata +23 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0feb4042406ce9043aa1f3f535da2ffbe4136197a28800f805e43860e43755a4
|
4
|
+
data.tar.gz: 8ec823251fe7a8c26223a7bc856b83263437833bf90938e6ff065ede68be97dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5755adcd86b0cb11c12e192542a10731dbfe3a00414bc901a652bd08a23b28bb1ba39a392f95a52b8c830c9132bc87b610e2381d1e01c9ceffd6c5009f136ce5
|
7
|
+
data.tar.gz: 7d72b95b3153cb54c28cfe808e24de5351a0c9327076b1b6dd1b1a8237a4ef29a9d1e456c0c9d9f5128d6fc1aae354b6956167516015d759855baa35d774a1ca
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -207,9 +207,16 @@ The following capabilities are currently supported.
|
|
207
207
|
|
208
208
|
Required feature: xpath
|
209
209
|
|
210
|
+
- urn:ietf:params:netconf:capability:notification:1.0
|
211
|
+
|
212
|
+
Required feature: notification
|
213
|
+
|
214
|
+
Required datastore operations:
|
215
|
+
- create-subscription
|
216
|
+
|
210
217
|
## Contributing
|
211
218
|
|
212
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
219
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hirura/hrr_rb_netconf. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
213
220
|
|
214
221
|
## Code of Conduct
|
215
222
|
|
data/hrr_rb_netconf.gemspec
CHANGED
@@ -22,7 +22,9 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.required_ruby_version = '>= 2.0.0'
|
24
24
|
|
25
|
-
spec.
|
25
|
+
spec.add_dependency "hrr_rb_relaxed_xml"
|
26
|
+
|
27
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
26
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
27
29
|
spec.add_development_dependency "simplecov", "~> 0.16"
|
28
30
|
end
|
@@ -121,7 +121,7 @@ module HrrRbNetconf
|
|
121
121
|
end
|
122
122
|
@logger.debug { "Sending message: #{buf.inspect}" }
|
123
123
|
begin
|
124
|
-
@io_w.write "#{buf}\n]]>]]
|
124
|
+
@io_w.write "#{buf}\n]]>]]>"
|
125
125
|
rescue => e
|
126
126
|
@logger.info { "Sender IO closed: #{e.class}: #{e.message}" }
|
127
127
|
raise IOError, "Sender IO closed: #{e.class}: #{e.message}"
|
@@ -9,15 +9,8 @@ module HrrRbNetconf
|
|
9
9
|
DEPENDENCIES = ['urn:ietf:params:netconf:capability:candidate:1.0']
|
10
10
|
IF_FEATURES = ['candidate', 'confirmed-commit']
|
11
11
|
|
12
|
-
oper_proc('cancel-commit'){ |session, datastore, input_e|
|
13
|
-
datastore.run 'cancel-commit', input_e
|
14
|
-
'<ok />'
|
15
|
-
}
|
16
|
-
|
17
12
|
model 'commit', ['confirmed'], 'leaf', 'type' => 'empty'
|
18
13
|
model 'commit', ['confirm-timeout'], 'leaf', 'type' => 'integer', 'range' => [1, 2**32-1], 'default' => '600'
|
19
|
-
model 'commit', ['persist'], 'leaf', 'type' => 'string'
|
20
|
-
model 'commit', ['persist-id'], 'leaf', 'type' => 'string'
|
21
14
|
end
|
22
15
|
end
|
23
16
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'hrr_rb_netconf/logger'
|
6
|
+
|
7
|
+
module HrrRbNetconf
|
8
|
+
class Server
|
9
|
+
class Capability
|
10
|
+
class Notification_1_0 < Capability
|
11
|
+
ID = 'urn:ietf:params:netconf:capability:notification:1.0'
|
12
|
+
DEPENDENCIES = []
|
13
|
+
IF_FEATURES = ['notification']
|
14
|
+
|
15
|
+
oper_proc('create-subscription'){ |session, datastore, input_e|
|
16
|
+
logger = Logger.new HrrRbNetconf::Server::Capability::Notification_1_0
|
17
|
+
stream_e = input_e.elements['stream']
|
18
|
+
unless stream_e
|
19
|
+
logger.debug { "create-subscription doesn't have stream, so use NETCONF stream" }
|
20
|
+
stream_e = input_e.add_element('stream')
|
21
|
+
stream_e.text = 'NETCONF'
|
22
|
+
end
|
23
|
+
stream = stream_e.text
|
24
|
+
start_time_e = input_e.elements['startTime']
|
25
|
+
start_time = unless start_time_e
|
26
|
+
nil
|
27
|
+
else
|
28
|
+
DateTime.rfc3339(start_time_e.text)
|
29
|
+
end
|
30
|
+
stop_time_e = input_e.elements['stopTime']
|
31
|
+
stop_time = unless stop_time_e
|
32
|
+
nil
|
33
|
+
else
|
34
|
+
DateTime.rfc3339(stop_time_e.text)
|
35
|
+
end
|
36
|
+
if ! session.subscription_creatable? stream
|
37
|
+
logger.error { "Not available stream: #{stream}" }
|
38
|
+
raise Error['bad-element'].new('protocol', 'error', info: {'bad-element' => 'stream'})
|
39
|
+
end
|
40
|
+
if start_time.nil? && stop_time
|
41
|
+
logger.error { "startTime element doesn't exist, but stopTime does" }
|
42
|
+
raise Error['missing-element'].new('protocol', 'error', info: {'bad-element' => 'startTime'})
|
43
|
+
end
|
44
|
+
if start_time && stop_time && (start_time > stop_time)
|
45
|
+
logger.error { "stopTime is earlier than startTime" }
|
46
|
+
raise Error['bad-element'].new('protocol', 'error', info: {'bad-element' => 'stopTime'})
|
47
|
+
end
|
48
|
+
if start_time && (start_time > DateTime.now)
|
49
|
+
logger.error { "startTime is later than current time" }
|
50
|
+
raise Error['bad-element'].new('protocol', 'error', info: {'bad-element' => 'startTime'})
|
51
|
+
end
|
52
|
+
begin
|
53
|
+
events = datastore.run('create-subscription', input_e)
|
54
|
+
rescue Error
|
55
|
+
raise
|
56
|
+
rescue => e
|
57
|
+
logger.error { "Exception in datastore.run('create-subscription', input_e): #{e.message}" }
|
58
|
+
raise Error['operation-failed'].new('application', 'error')
|
59
|
+
end
|
60
|
+
begin
|
61
|
+
if start_time
|
62
|
+
session.notification_replay stream, start_time, stop_time, events
|
63
|
+
end
|
64
|
+
rescue Error
|
65
|
+
raise
|
66
|
+
rescue => e
|
67
|
+
logger.error { "Exception in session.notification_replay: #{e.message}" }
|
68
|
+
raise Error['operation-failed'].new('protocol', 'error')
|
69
|
+
end
|
70
|
+
session.create_subscription stream, start_time, stop_time
|
71
|
+
'<ok />'
|
72
|
+
}
|
73
|
+
|
74
|
+
model 'create-subscription', ['stream'], 'leaf', 'type' => 'string'
|
75
|
+
model 'create-subscription', ['filter'], 'leaf', 'type' => 'anyxml'
|
76
|
+
model 'create-subscription', ['startTime'], 'leaf', 'type' => 'string'
|
77
|
+
model 'create-subscription', ['stopTime'], 'leaf', 'type' => 'string'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -14,7 +14,6 @@ module HrrRbNetconf
|
|
14
14
|
'<ok />'
|
15
15
|
}
|
16
16
|
|
17
|
-
model 'edit-config', ['test-option'], 'leaf', 'type' => 'enumeration', 'enum' => ['test-then-set', 'set', 'test-only'], 'default' => 'test-then-set'
|
18
17
|
model 'validate', ['source'], 'container'
|
19
18
|
model 'validate', ['source', 'config-source'], 'choice', 'mandatory' => true
|
20
19
|
model 'validate', ['source', 'config-source', 'running'], 'leaf', 'type' => 'empty'
|
@@ -204,3 +204,4 @@ require 'hrr_rb_netconf/server/capability/validate_1_0'
|
|
204
204
|
require 'hrr_rb_netconf/server/capability/validate_1_1'
|
205
205
|
require 'hrr_rb_netconf/server/capability/url_1_0'
|
206
206
|
require 'hrr_rb_netconf/server/capability/xpath_1_0'
|
207
|
+
require 'hrr_rb_netconf/server/capability/notification_1_0'
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_relaxed_xml'
|
5
|
+
require 'hrr_rb_netconf/logger'
|
6
|
+
|
7
|
+
module HrrRbNetconf
|
8
|
+
class Server
|
9
|
+
class NotificationEvent
|
10
|
+
def initialize arg1, arg2=nil
|
11
|
+
unless arg2
|
12
|
+
@event_xml = case arg1
|
13
|
+
when HrrRbRelaxedXML::Document
|
14
|
+
arg1
|
15
|
+
else
|
16
|
+
HrrRbRelaxedXML::Document.new(arg2, {:ignore_whitespace_nodes => :all})
|
17
|
+
end
|
18
|
+
event_time = @event_xml.elements['eventTime'].text
|
19
|
+
@event_xml.elements['eventTime'].text = DateTime.parse(event_time).rfc3339
|
20
|
+
else
|
21
|
+
event_time_e = REXML::Element.new('eventTime')
|
22
|
+
event_time_e.text = case arg1
|
23
|
+
when REXML::Element
|
24
|
+
DateTime.parse(arg1.text).rfc3339
|
25
|
+
else
|
26
|
+
DateTime.parse(arg1.to_s).rfc3339
|
27
|
+
end
|
28
|
+
event_e = case arg2
|
29
|
+
when REXML::Document
|
30
|
+
arg2.root.deep_clone
|
31
|
+
when REXML::Element
|
32
|
+
arg2.deep_clone
|
33
|
+
else
|
34
|
+
REXML::Document.new(arg2, {:ignore_whitespace_nodes => :all}).root
|
35
|
+
end
|
36
|
+
@event_xml = HrrRbRelaxedXML::Document.new
|
37
|
+
@event_xml.add event_time_e
|
38
|
+
@event_xml.add event_e
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_xml
|
43
|
+
@event_xml
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbNetconf
|
5
|
+
class Server
|
6
|
+
class NotificationStream
|
7
|
+
attr_reader :blk
|
8
|
+
|
9
|
+
def initialize blk, replay_support
|
10
|
+
@blk = blk
|
11
|
+
@replay_support = replay_support
|
12
|
+
end
|
13
|
+
|
14
|
+
def match? event_xml
|
15
|
+
if @blk.call(event_xml)
|
16
|
+
true
|
17
|
+
else
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def support_replay?
|
23
|
+
@replay_support
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_netconf/logger'
|
5
|
+
require 'hrr_rb_netconf/server/notification_stream'
|
6
|
+
|
7
|
+
module HrrRbNetconf
|
8
|
+
class Server
|
9
|
+
class NotificationStreams
|
10
|
+
def initialize
|
11
|
+
@streams = Hash.new
|
12
|
+
@streams['NETCONF'] = NotificationStream.new(Proc.new { true }, false)
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_stream? stream
|
16
|
+
@streams.has_key? stream
|
17
|
+
end
|
18
|
+
|
19
|
+
def stream_support_replay? stream
|
20
|
+
@streams[stream].support_replay?
|
21
|
+
end
|
22
|
+
|
23
|
+
def update stream, blk, replay_support
|
24
|
+
if blk.nil? && (! @streams.has_key?( stream ))
|
25
|
+
raise ArgumentError, "Requires block for new stream: #{stream}"
|
26
|
+
end
|
27
|
+
blk ||= @streams[stream].blk
|
28
|
+
@streams[stream] = NotificationStream.new(blk, replay_support)
|
29
|
+
end
|
30
|
+
|
31
|
+
def matched_streams event_xml
|
32
|
+
@streams.select{ |k, v| v.match? event_xml }.keys
|
33
|
+
end
|
34
|
+
|
35
|
+
def event_match_stream? event_xml, stream
|
36
|
+
@streams[stream].match? event_xml
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,7 +1,12 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
+
require 'time'
|
5
|
+
require 'date'
|
6
|
+
require 'thread'
|
7
|
+
require 'monitor'
|
4
8
|
require 'rexml/document'
|
9
|
+
require 'hrr_rb_relaxed_xml'
|
5
10
|
require 'hrr_rb_netconf/logger'
|
6
11
|
require 'hrr_rb_netconf/server/capability'
|
7
12
|
require 'hrr_rb_netconf/server/operation'
|
@@ -28,6 +33,12 @@ module HrrRbNetconf
|
|
28
33
|
end
|
29
34
|
@strict_capabilities = strict_capabilities
|
30
35
|
@closed = false
|
36
|
+
@notification_enabled = false
|
37
|
+
@monitor = Monitor.new
|
38
|
+
@subscribed_streams = Hash.new
|
39
|
+
@subscribed_streams_stop_time = Hash.new
|
40
|
+
@notification_replay_thread = nil
|
41
|
+
@subscription_termination_thread = nil
|
31
42
|
end
|
32
43
|
|
33
44
|
def start
|
@@ -46,10 +57,10 @@ module HrrRbNetconf
|
|
46
57
|
def close
|
47
58
|
@logger.info { "Being closed" }
|
48
59
|
@closed = true
|
49
|
-
|
50
|
-
|
51
|
-
rescue
|
52
|
-
|
60
|
+
@io_r.close_read rescue nil
|
61
|
+
@notification_replay_thread.exit if @notification_replay_thread rescue nil
|
62
|
+
@notification_termination_thread.exit if @notification_termination_thread rescue nil
|
63
|
+
@logger.info { "Closed" }
|
53
64
|
end
|
54
65
|
|
55
66
|
def closed?
|
@@ -79,7 +90,7 @@ module HrrRbNetconf
|
|
79
90
|
formatter.compact = true
|
80
91
|
formatter.write(xml_doc, buf)
|
81
92
|
@logger.debug { "Sending hello message: #{buf.inspect}" }
|
82
|
-
@io_w.write "#{buf}\n]]>]]
|
93
|
+
@io_w.write "#{buf}\n]]>]]>"
|
83
94
|
end
|
84
95
|
|
85
96
|
def receive_hello
|
@@ -118,45 +129,40 @@ module HrrRbNetconf
|
|
118
129
|
|
119
130
|
begin
|
120
131
|
loop do
|
121
|
-
if closed?
|
122
|
-
break
|
123
|
-
end
|
124
|
-
|
132
|
+
break if closed?
|
125
133
|
begin
|
134
|
+
received_message = @receiver.receive_message
|
135
|
+
break unless received_message
|
136
|
+
rescue Error => e
|
137
|
+
rpc_reply_e = REXML::Element.new("rpc-reply")
|
138
|
+
rpc_reply_e.add_namespace("urn:ietf:params:xml:ns:netconf:base:1.0")
|
139
|
+
rpc_reply_e.add e.to_rpc_error
|
140
|
+
rescue => e
|
141
|
+
@logger.error { e.message }
|
142
|
+
raise
|
143
|
+
end
|
144
|
+
@monitor.synchronize do
|
126
145
|
begin
|
127
|
-
received_message = @receiver.receive_message
|
128
|
-
break unless received_message
|
129
146
|
rpc_reply_e = operation.run received_message
|
130
147
|
rescue Error => e
|
131
|
-
|
132
|
-
|
133
|
-
rpc_reply_e.name = "rpc-reply"
|
134
|
-
else
|
135
|
-
rpc_reply_e = REXML::Element.new("rpc-reply")
|
136
|
-
rpc_reply_e.add_namespace("urn:ietf:params:xml:ns:netconf:base:1.0")
|
137
|
-
end
|
148
|
+
rpc_reply_e = received_message.clone
|
149
|
+
rpc_reply_e.name = "rpc-reply"
|
138
150
|
rpc_reply_e.add e.to_rpc_error
|
151
|
+
rescue => e
|
152
|
+
@logger.error { e.message }
|
153
|
+
raise
|
154
|
+
ensure
|
155
|
+
begin
|
156
|
+
@sender.send_message rpc_reply_e if rpc_reply_e
|
157
|
+
rescue IOError
|
158
|
+
break
|
159
|
+
end
|
139
160
|
end
|
140
|
-
|
141
|
-
begin
|
142
|
-
@sender.send_message rpc_reply_e
|
143
|
-
rescue IOError
|
144
|
-
break
|
145
|
-
end
|
146
|
-
rescue => e
|
147
|
-
@logger.error { e.message }
|
148
|
-
raise
|
149
161
|
end
|
150
162
|
end
|
151
163
|
ensure
|
152
|
-
|
153
|
-
|
154
|
-
rescue
|
155
|
-
end
|
156
|
-
begin
|
157
|
-
@io_w.close_write
|
158
|
-
rescue
|
159
|
-
end
|
164
|
+
datastore_session.close rescue nil
|
165
|
+
@io_w.close_write rescue nil
|
160
166
|
end
|
161
167
|
@logger.info { "Exit operation_loop" }
|
162
168
|
end
|
@@ -172,6 +178,144 @@ module HrrRbNetconf
|
|
172
178
|
def unlock target
|
173
179
|
@server.unlock target, @session_id
|
174
180
|
end
|
181
|
+
|
182
|
+
def subscription_creatable? stream
|
183
|
+
@logger.info { "Check subscription for stream: #{stream}" }
|
184
|
+
if ! @server.has_notification_stream? stream
|
185
|
+
@logger.error { "Server doesn't have notification stream: #{stream}" }
|
186
|
+
false
|
187
|
+
elsif @subscribed_streams.has_key? stream
|
188
|
+
@logger.error { "Session already has subscription for stream: #{stream}" }
|
189
|
+
false
|
190
|
+
else
|
191
|
+
@logger.info { "Subscription creatable for stream: #{stream}" }
|
192
|
+
true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def create_subscription stream, start_time, stop_time
|
197
|
+
@logger.info { "Create subscription for stream: #{stream}" }
|
198
|
+
@subscribed_streams[stream] = true
|
199
|
+
start_notification_termination_thread stream, start_time, stop_time if stop_time
|
200
|
+
@logger.info { "Create subscription done for stream: #{stream}" }
|
201
|
+
end
|
202
|
+
|
203
|
+
def terminate_subscription stream
|
204
|
+
@logger.info { "Terminate subscription for stream: #{stream}" }
|
205
|
+
@subscribed_streams.delete stream
|
206
|
+
@logger.info { "Terminate subscription done for stream: #{stream}" }
|
207
|
+
end
|
208
|
+
|
209
|
+
def notification_replay stream, start_time, stop_time, events
|
210
|
+
if @server.notification_stream_support_replay? stream
|
211
|
+
start_notification_replay_thread stream, start_time, stop_time, events
|
212
|
+
else
|
213
|
+
@logger.error { "Notification replay is not supported by stream: #{stream}" }
|
214
|
+
raise Error['operation-failed'].new('protocol', 'error')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def stream_subscribed? stream
|
219
|
+
@subscribed_streams.has_key? stream
|
220
|
+
end
|
221
|
+
|
222
|
+
def start_notification_replay_thread stream, start_time, stop_time, events
|
223
|
+
@notification_replay_thread = Thread.new do
|
224
|
+
@logger.info { "Notification replay start for stream: #{stream}" }
|
225
|
+
begin
|
226
|
+
@monitor.synchronize do
|
227
|
+
unless events.respond_to? :each
|
228
|
+
@logger.error { "Argument `events' doesn't respond to :each method: #{events}" }
|
229
|
+
else
|
230
|
+
begin
|
231
|
+
events.each{ |arg1, arg2|
|
232
|
+
event_xml = NotificationEvent.new(arg1, arg2).to_xml
|
233
|
+
if @server.event_match_stream? event_xml, stream
|
234
|
+
if start_time
|
235
|
+
event_time = DateTime.rfc3339(event_xml.elements['eventTime'].text)
|
236
|
+
if start_time < event_time
|
237
|
+
if stop_time.nil? || event_time < stop_time
|
238
|
+
send_notification event_xml
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
}
|
244
|
+
rescue => e
|
245
|
+
@logger.error { "Got an exception during processing replay: #{e.message}" }
|
246
|
+
end
|
247
|
+
end
|
248
|
+
send_replay_complete stream
|
249
|
+
end
|
250
|
+
ensure
|
251
|
+
@logger.info { "Notification replay completed for stream: #{stream}" }
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def start_notification_termination_thread stream, start_time, stop_time
|
257
|
+
@notification_termination_thread = Thread.new do
|
258
|
+
@logger.info { "Notification termination thread start for stream: #{stream}" }
|
259
|
+
begin
|
260
|
+
loop do
|
261
|
+
now = DateTime.now
|
262
|
+
if now.to_time < stop_time.to_time
|
263
|
+
sleep_time = ((stop_time.to_time - now.to_time) / 2.0).ceil
|
264
|
+
@logger.debug { "Notification termination thread for stream: #{stream}: sleep [sec]: #{sleep_time}" }
|
265
|
+
sleep sleep_time
|
266
|
+
else
|
267
|
+
@logger.info { "Notification termination thread terminates subscription for stream: #{stream}" }
|
268
|
+
@monitor.synchronize do
|
269
|
+
terminate_subscription stream
|
270
|
+
send_notification_complete stream
|
271
|
+
end
|
272
|
+
break
|
273
|
+
end
|
274
|
+
end
|
275
|
+
ensure
|
276
|
+
@logger.info { "Notification termination completed for stream: #{stream}" }
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def send_notification event_e
|
282
|
+
@monitor.synchronize do
|
283
|
+
notif_e = REXML::Element.new("notification")
|
284
|
+
notif_e.add_namespace("urn:ietf:params:xml:ns:netconf:notification:1.0")
|
285
|
+
event_e.elements.each{ |e|
|
286
|
+
notif_e.add e.deep_clone
|
287
|
+
}
|
288
|
+
begin
|
289
|
+
@sender.send_message notif_e
|
290
|
+
rescue IOError => e
|
291
|
+
@logger.warn { "Failed sending notification: #{e.message}" }
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def filter_and_send_notification matched_streams, event_xml
|
297
|
+
unless (matched_streams & @subscribed_streams.keys).empty?
|
298
|
+
#event_e = filter(event_xml)
|
299
|
+
event_e = event_xml
|
300
|
+
send_notification event_e
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def send_replay_complete stream
|
305
|
+
event_xml = HrrRbRelaxedXML::Document.new
|
306
|
+
event_time_e = event_xml.add_element('eventTime')
|
307
|
+
event_time_e.text = DateTime.now.rfc3339
|
308
|
+
event_e = event_xml.add_element("replayComplete")
|
309
|
+
send_notification event_xml
|
310
|
+
end
|
311
|
+
|
312
|
+
def send_notification_complete stream
|
313
|
+
event_xml = HrrRbRelaxedXML::Document.new
|
314
|
+
event_time_e = event_xml.add_element('eventTime')
|
315
|
+
event_time_e.text = DateTime.now.rfc3339
|
316
|
+
event_e = event_xml.add_element("notificationComplete")
|
317
|
+
send_notification event_xml
|
318
|
+
end
|
175
319
|
end
|
176
320
|
end
|
177
321
|
end
|
@@ -1,13 +1,17 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
|
+
require 'date'
|
4
5
|
require 'thread'
|
6
|
+
require 'hrr_rb_relaxed_xml'
|
5
7
|
require 'hrr_rb_netconf/logger'
|
6
8
|
require 'hrr_rb_netconf/server/error'
|
7
9
|
require 'hrr_rb_netconf/server/errors'
|
8
10
|
require 'hrr_rb_netconf/server/datastore'
|
9
11
|
require 'hrr_rb_netconf/server/capabilities'
|
10
12
|
require 'hrr_rb_netconf/server/session'
|
13
|
+
require 'hrr_rb_netconf/server/notification_event'
|
14
|
+
require 'hrr_rb_netconf/server/notification_streams'
|
11
15
|
|
12
16
|
module HrrRbNetconf
|
13
17
|
class Server
|
@@ -26,6 +30,7 @@ module HrrRbNetconf
|
|
26
30
|
@locks = Hash.new
|
27
31
|
@lock_mutex = Mutex.new
|
28
32
|
@last_session_id = SESSION_ID_MIN - 1
|
33
|
+
@notification_streams = NotificationStreams.new
|
29
34
|
end
|
30
35
|
|
31
36
|
def allocate_session_id
|
@@ -44,7 +49,7 @@ module HrrRbNetconf
|
|
44
49
|
end
|
45
50
|
|
46
51
|
def start_session io
|
47
|
-
@logger.info { "
|
52
|
+
@logger.info { "Start session" }
|
48
53
|
session_id = SESSION_ID_UNALLOCATED
|
49
54
|
begin
|
50
55
|
@mutex.synchronize do
|
@@ -52,11 +57,7 @@ module HrrRbNetconf
|
|
52
57
|
@logger.info { "Session ID: #{session_id}" }
|
53
58
|
@sessions[session_id] = Session.new self, @capabilities, @datastore, session_id, io, @strict_capabilities
|
54
59
|
end
|
55
|
-
|
56
|
-
@sessions[session_id].start
|
57
|
-
}
|
58
|
-
@logger.info { "Session started: Session ID: #{session_id}" }
|
59
|
-
t.join
|
60
|
+
@sessions[session_id].start
|
60
61
|
rescue => e
|
61
62
|
@logger.error { "Session terminated: Session ID: #{session_id}" }
|
62
63
|
raise
|
@@ -105,5 +106,32 @@ module HrrRbNetconf
|
|
105
106
|
end
|
106
107
|
end
|
107
108
|
end
|
109
|
+
|
110
|
+
def notification_stream stream, replay_support: false, &blk
|
111
|
+
@notification_streams.update stream, blk, replay_support
|
112
|
+
end
|
113
|
+
|
114
|
+
def has_notification_stream? stream
|
115
|
+
@notification_streams.has_stream? stream
|
116
|
+
end
|
117
|
+
|
118
|
+
def notification_stream_support_replay? stream
|
119
|
+
@notification_streams.stream_support_replay? stream
|
120
|
+
end
|
121
|
+
|
122
|
+
def event_match_stream? event_xml, stream
|
123
|
+
@notification_streams.event_match_stream? event_xml, stream
|
124
|
+
end
|
125
|
+
|
126
|
+
def send_notification arg1, arg2=nil
|
127
|
+
event_xml = NotificationEvent.new(arg1, arg2).to_xml
|
128
|
+
matched_streams = @notification_streams.matched_streams event_xml
|
129
|
+
@logger.info { "Send notification" }
|
130
|
+
@logger.debug { "Event time: #{event_xml.elements['eventTime'].text}, Event: #{event_xml.elements.to_a}" }
|
131
|
+
@sessions.each{ |session_id, session|
|
132
|
+
session.filter_and_send_notification matched_streams, event_xml
|
133
|
+
}
|
134
|
+
@logger.info { "Send notification done" }
|
135
|
+
end
|
108
136
|
end
|
109
137
|
end
|
metadata
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hrr_rb_netconf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hirura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hrr_rb_relaxed_xml
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - "~>"
|
18
32
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
33
|
+
version: '12.0'
|
20
34
|
type: :development
|
21
35
|
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
40
|
+
version: '12.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rspec
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,6 +96,7 @@ files:
|
|
82
96
|
- lib/hrr_rb_netconf/server/capability/candidate_1_0.rb
|
83
97
|
- lib/hrr_rb_netconf/server/capability/confirmed_commit_1_0.rb
|
84
98
|
- lib/hrr_rb_netconf/server/capability/confirmed_commit_1_1.rb
|
99
|
+
- lib/hrr_rb_netconf/server/capability/notification_1_0.rb
|
85
100
|
- lib/hrr_rb_netconf/server/capability/rollback_on_error_1_0.rb
|
86
101
|
- lib/hrr_rb_netconf/server/capability/startup_1_0.rb
|
87
102
|
- lib/hrr_rb_netconf/server/capability/url_1_0.rb
|
@@ -120,6 +135,9 @@ files:
|
|
120
135
|
- lib/hrr_rb_netconf/server/filter/xpath.rb
|
121
136
|
- lib/hrr_rb_netconf/server/model.rb
|
122
137
|
- lib/hrr_rb_netconf/server/model/node.rb
|
138
|
+
- lib/hrr_rb_netconf/server/notification_event.rb
|
139
|
+
- lib/hrr_rb_netconf/server/notification_stream.rb
|
140
|
+
- lib/hrr_rb_netconf/server/notification_streams.rb
|
123
141
|
- lib/hrr_rb_netconf/server/operation.rb
|
124
142
|
- lib/hrr_rb_netconf/server/session.rb
|
125
143
|
- lib/hrr_rb_netconf/version.rb
|
@@ -142,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
160
|
- !ruby/object:Gem::Version
|
143
161
|
version: '0'
|
144
162
|
requirements: []
|
145
|
-
rubygems_version: 3.
|
163
|
+
rubygems_version: 3.1.2
|
146
164
|
signing_key:
|
147
165
|
specification_version: 4
|
148
166
|
summary: Pure Ruby NETCONF server implementation
|