hrr_rb_netconf 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +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
|