hrr_rb_netconf 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.rspec +3 -0
- data/.travis.yml +32 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +201 -0
- data/README.md +220 -0
- data/Rakefile +6 -0
- data/demo/server.rb +54 -0
- data/demo/server_over_ssh.rb +97 -0
- data/demo/server_with_session-oriented-database.rb +134 -0
- data/demo/server_with_sessionless-database.rb +81 -0
- data/hrr_rb_netconf.gemspec +28 -0
- data/lib/hrr_rb_netconf.rb +10 -0
- data/lib/hrr_rb_netconf/logger.rb +56 -0
- data/lib/hrr_rb_netconf/server.rb +109 -0
- data/lib/hrr_rb_netconf/server/capabilities.rb +75 -0
- data/lib/hrr_rb_netconf/server/capability.rb +206 -0
- data/lib/hrr_rb_netconf/server/capability/base_1_0.rb +183 -0
- data/lib/hrr_rb_netconf/server/capability/base_1_1.rb +247 -0
- data/lib/hrr_rb_netconf/server/capability/candidate_1_0.rb +34 -0
- data/lib/hrr_rb_netconf/server/capability/confirmed_commit_1_0.rb +24 -0
- data/lib/hrr_rb_netconf/server/capability/confirmed_commit_1_1.rb +24 -0
- data/lib/hrr_rb_netconf/server/capability/rollback_on_error_1_0.rb +16 -0
- data/lib/hrr_rb_netconf/server/capability/startup_1_0.rb +22 -0
- data/lib/hrr_rb_netconf/server/capability/url_1_0.rb +23 -0
- data/lib/hrr_rb_netconf/server/capability/validate_1_0.rb +25 -0
- data/lib/hrr_rb_netconf/server/capability/validate_1_1.rb +25 -0
- data/lib/hrr_rb_netconf/server/capability/writable_running_1_0.rb +17 -0
- data/lib/hrr_rb_netconf/server/capability/xpath_1_0.rb +14 -0
- data/lib/hrr_rb_netconf/server/datastore.rb +30 -0
- data/lib/hrr_rb_netconf/server/datastore/oper_handler.rb +29 -0
- data/lib/hrr_rb_netconf/server/datastore/session.rb +52 -0
- data/lib/hrr_rb_netconf/server/error.rb +52 -0
- data/lib/hrr_rb_netconf/server/error/access_denied.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/bad_attribute.rb +20 -0
- data/lib/hrr_rb_netconf/server/error/bad_element.rb +20 -0
- data/lib/hrr_rb_netconf/server/error/data_exists.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/data_missing.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/in_use.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/invalid_value.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/lock_denied.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/malformed_message.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/missing_attribute.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/missing_element.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/operation_failed.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/operation_not_supported.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/partial_operation.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/resource_denied.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/rollback_failed.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/rpc_errorable.rb +138 -0
- data/lib/hrr_rb_netconf/server/error/too_big.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/unknown_attribute.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/unknown_element.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/unknown_namespace.rb +19 -0
- data/lib/hrr_rb_netconf/server/errors.rb +28 -0
- data/lib/hrr_rb_netconf/server/filter.rb +48 -0
- data/lib/hrr_rb_netconf/server/filter/subtree.rb +135 -0
- data/lib/hrr_rb_netconf/server/filter/xpath.rb +59 -0
- data/lib/hrr_rb_netconf/server/model.rb +123 -0
- data/lib/hrr_rb_netconf/server/model/node.rb +19 -0
- data/lib/hrr_rb_netconf/server/operation.rb +92 -0
- data/lib/hrr_rb_netconf/server/session.rb +177 -0
- data/lib/hrr_rb_netconf/version.rb +6 -0
- metadata +149 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'rexml/document'
|
5
|
+
|
6
|
+
module HrrRbNetconf
|
7
|
+
class Server
|
8
|
+
class Filter
|
9
|
+
class Xpath < Filter
|
10
|
+
TYPE = 'xpath'
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def filter raw_output_e, filter_e
|
14
|
+
xpath = filter_e.attributes['select']
|
15
|
+
unless xpath
|
16
|
+
raise Error['missing-attribute'].new('protocol', 'error', info: {'bad-attribute' => 'select', 'bad-element' => 'filter'})
|
17
|
+
end
|
18
|
+
raw_output_xml_doc = REXML::Document.new
|
19
|
+
raw_output_xml_doc.add raw_output_e.deep_clone
|
20
|
+
selected_element_xpaths = []
|
21
|
+
output_xml_doc = REXML::Document.new
|
22
|
+
raw_output_xml_doc.each_element(xpath){ |e|
|
23
|
+
ctx_output_e = add_ancestors_recursively selected_element_xpaths, output_xml_doc, e
|
24
|
+
e.children.each{ |c|
|
25
|
+
case c
|
26
|
+
when REXML::Parent
|
27
|
+
ctx_output_e.add c.deep_clone
|
28
|
+
else
|
29
|
+
ctx_output_e.add c.clone
|
30
|
+
end
|
31
|
+
}
|
32
|
+
}
|
33
|
+
output_xml_doc.root
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_elem selected_element_xpaths, output_e, raw_output_e
|
37
|
+
xpath, elem = selected_element_xpaths.find{ |xpath, elem| xpath == raw_output_e.xpath }
|
38
|
+
unless xpath
|
39
|
+
child_output_e = output_e.add raw_output_e.clone
|
40
|
+
selected_element_xpaths.push [raw_output_e.xpath, child_output_e]
|
41
|
+
child_output_e
|
42
|
+
else
|
43
|
+
elem
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_ancestors_recursively selected_element_xpaths, output_e, raw_output_e
|
48
|
+
if raw_output_e == raw_output_e.root_node
|
49
|
+
output_e
|
50
|
+
else
|
51
|
+
parent_e = add_ancestors_recursively selected_element_xpaths, output_e, raw_output_e.parent
|
52
|
+
add_elem selected_element_xpaths, parent_e, raw_output_e
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'hrr_rb_netconf/server/error'
|
6
|
+
require 'hrr_rb_netconf/server/model/node'
|
7
|
+
|
8
|
+
module HrrRbNetconf
|
9
|
+
class Server
|
10
|
+
class Model
|
11
|
+
def initialize operation
|
12
|
+
@operation = operation
|
13
|
+
@tree = Node.new nil, operation, 'root', {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_recursively capability, node, path, stmt, options
|
17
|
+
name = path.shift
|
18
|
+
case path.size
|
19
|
+
when 0
|
20
|
+
node.children.push Node.new capability, name, stmt, options
|
21
|
+
else
|
22
|
+
child_node = node.children.find{|n| name == n.name}
|
23
|
+
add_recursively capability, child_node, path, stmt, options
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add capability, path, stmt, options
|
28
|
+
if path.size > 0
|
29
|
+
add_recursively capability, @tree, path.dup, stmt, options
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_recursively node, xml_e, parent_xml_e: nil, validated: []
|
34
|
+
case node.stmt
|
35
|
+
when 'root', 'container'
|
36
|
+
case xml_e
|
37
|
+
when nil
|
38
|
+
true
|
39
|
+
else
|
40
|
+
node.children.all?{ |c|
|
41
|
+
case c.stmt
|
42
|
+
when 'container'
|
43
|
+
validated.push c.name
|
44
|
+
validate_recursively c, xml_e.elements[c.name]
|
45
|
+
when 'leaf'
|
46
|
+
validated.push c.name
|
47
|
+
if xml_e.elements[c.name].nil? && c.options['default'].nil?
|
48
|
+
if c.options['validation'].nil?
|
49
|
+
true
|
50
|
+
else
|
51
|
+
raise Error['operation-failed'].new('application', 'error', message: 'Not implemented')
|
52
|
+
end
|
53
|
+
else
|
54
|
+
validate_recursively c, xml_e.elements[c.name], parent_xml_e: xml_e
|
55
|
+
end
|
56
|
+
when 'choice'
|
57
|
+
validate_recursively c, xml_e, validated: validated
|
58
|
+
else
|
59
|
+
raise Error['unknown-element'].new('application', 'error', info: {'bad-element' => "#{c.name}: #{c.stmt}"}, message: 'Not implemented')
|
60
|
+
end
|
61
|
+
}
|
62
|
+
end && (xml_e.elements.to_a.map{|e| e.name} - validated).empty?
|
63
|
+
when 'leaf'
|
64
|
+
case node.options['type']
|
65
|
+
when 'empty'
|
66
|
+
xml_e != nil && xml_e.has_text?.!
|
67
|
+
when 'enumeration'
|
68
|
+
if xml_e == nil && node.options['default']
|
69
|
+
parent_xml_e.add_element(node.name).text = node.options['default']
|
70
|
+
else
|
71
|
+
xml_e != nil && node.options['enum'].include?(xml_e.text)
|
72
|
+
end
|
73
|
+
when 'anyxml'
|
74
|
+
xml_e != nil && (REXML::Document.new(xml_e.text) rescue false)
|
75
|
+
when 'inet:uri'
|
76
|
+
xml_e != nil
|
77
|
+
raise Error['unknown-element'].new('application', 'error', info: {'bad-element' => "#{node.name}: #{node.stmt}"}, message: 'Not implemented: type inet:uri')
|
78
|
+
when 'integer'
|
79
|
+
if xml_e == nil && node.options['default']
|
80
|
+
parent_xml_e.add_element(node.name).text = node.options['default']
|
81
|
+
else
|
82
|
+
value = (Integer(xml_e.text) rescue false)
|
83
|
+
if node.options['range']
|
84
|
+
min, max = node.options['range']
|
85
|
+
xml_e != nil && value && min <= value && value <= max
|
86
|
+
else
|
87
|
+
xml_e != nil && value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
when 'string'
|
91
|
+
if xml_e == nil && node.options['default']
|
92
|
+
parent_xml_e.add_element(node.name).text = node.options['default']
|
93
|
+
else
|
94
|
+
if node.options['validation'].nil?
|
95
|
+
xml_e != nil && xml_e.has_text?
|
96
|
+
else
|
97
|
+
xml_e != nil && xml_e.has_text? && node.options['validation'].call(node.capability, xml_e)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when 'choice'
|
102
|
+
if node.options['mandatory']
|
103
|
+
node.children.any?{ |c|
|
104
|
+
validated.push c.name
|
105
|
+
validate_recursively c, xml_e.elements[c.name]
|
106
|
+
}
|
107
|
+
else
|
108
|
+
node.children.empty? || node.children.any?{ |c|
|
109
|
+
validated.push c.name
|
110
|
+
validate_recursively c, xml_e.elements[c.name]
|
111
|
+
}
|
112
|
+
end
|
113
|
+
else
|
114
|
+
raise Error['unknown-element'].new('application', 'error', info: {'bad-element' => "#{c.name}: #{c.stmt}"}, message: 'Not implemented')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def validate input_e
|
119
|
+
validate_recursively @tree, input_e
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbNetconf
|
5
|
+
class Server
|
6
|
+
class Model
|
7
|
+
class Node
|
8
|
+
attr_reader :capability, :name, :stmt, :options, :children
|
9
|
+
def initialize capability, name, stmt, options
|
10
|
+
@capability = capability
|
11
|
+
@name = name
|
12
|
+
@stmt = stmt
|
13
|
+
@options = options
|
14
|
+
@children = Array.new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'hrr_rb_netconf/logger'
|
5
|
+
require 'hrr_rb_netconf/server/model'
|
6
|
+
require 'hrr_rb_netconf/server/filter'
|
7
|
+
|
8
|
+
module HrrRbNetconf
|
9
|
+
class Server
|
10
|
+
class Operation
|
11
|
+
def initialize session, capabilities, datastore_session, strict_capabilities
|
12
|
+
@logger = Logger.new self.class.name
|
13
|
+
@session = session
|
14
|
+
@capabilities = capabilities
|
15
|
+
@datastore_session = datastore_session
|
16
|
+
@strict_capabilities = strict_capabilities
|
17
|
+
@models = Hash.new
|
18
|
+
@oper_procs = Hash.new
|
19
|
+
|
20
|
+
load_capabilities
|
21
|
+
end
|
22
|
+
|
23
|
+
def load_capabilities
|
24
|
+
@capabilities.each_loadable{ |c|
|
25
|
+
@logger.debug { "Load capability: #{c.id}" }
|
26
|
+
c.oper_procs.each{ |k, v|
|
27
|
+
@oper_procs[k] = v
|
28
|
+
}
|
29
|
+
if @strict_capabilities
|
30
|
+
c.models.each{ |m|
|
31
|
+
oper_name, path, stmt, options = m
|
32
|
+
@models[oper_name] ||= Model.new oper_name
|
33
|
+
@models[oper_name].add c, path, stmt, options
|
34
|
+
}
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate input_e
|
40
|
+
oper_name = input_e.name
|
41
|
+
model = @models[oper_name]
|
42
|
+
if model
|
43
|
+
model.validate input_e
|
44
|
+
else
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def run xml_doc
|
50
|
+
unless xml_doc.root.name == 'rpc'
|
51
|
+
@logger.error { "Invalid root tag: must be rpc, but got #{xml_doc.root.name}" }
|
52
|
+
raise Error['operation-not-supported'].new('protocol', 'error')
|
53
|
+
end
|
54
|
+
|
55
|
+
message_id = xml_doc.attributes['message-id']
|
56
|
+
unless message_id
|
57
|
+
raise Error['missing-attribute'].new('rpc', 'error', info: {'bad-attribute' => 'message-id', 'bad-element' => 'rpc'})
|
58
|
+
end
|
59
|
+
|
60
|
+
input_e = xml_doc.elements[1]
|
61
|
+
|
62
|
+
unless @oper_procs.has_key? input_e.name
|
63
|
+
raise Error['operation-not-supported'].new('protocol', 'error')
|
64
|
+
end
|
65
|
+
|
66
|
+
if @strict_capabilities
|
67
|
+
unless validate input_e
|
68
|
+
raise Error['operation-not-supported'].new('application', 'error')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
raw_output = @oper_procs[input_e.name].call(@session, @datastore_session, input_e)
|
73
|
+
|
74
|
+
raw_output_e = case raw_output
|
75
|
+
when String
|
76
|
+
REXML::Document.new(raw_output, {:ignore_whitespace_nodes => :all}).root
|
77
|
+
when REXML::Document
|
78
|
+
raw_output.root
|
79
|
+
when REXML::Element
|
80
|
+
raw_output
|
81
|
+
else
|
82
|
+
raise "Unexpected output: #{raw_output.inspect}"
|
83
|
+
end
|
84
|
+
output_e = Filter.filter(raw_output_e, input_e)
|
85
|
+
rpc_reply_e = xml_doc.clone
|
86
|
+
rpc_reply_e.name = "rpc-reply"
|
87
|
+
rpc_reply_e.add output_e
|
88
|
+
rpc_reply_e
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'hrr_rb_netconf/logger'
|
6
|
+
require 'hrr_rb_netconf/server/capability'
|
7
|
+
require 'hrr_rb_netconf/server/operation'
|
8
|
+
|
9
|
+
module HrrRbNetconf
|
10
|
+
class Server
|
11
|
+
class Session
|
12
|
+
attr_reader :session_id
|
13
|
+
|
14
|
+
def initialize server, capabilities, datastore, session_id, io, strict_capabilities
|
15
|
+
@logger = Logger.new self.class.name
|
16
|
+
@server = server
|
17
|
+
@local_capabilities = capabilities
|
18
|
+
@remote_capabilities = Array.new
|
19
|
+
@datastore = datastore
|
20
|
+
@session_id = session_id
|
21
|
+
@io_r, @io_w = case io
|
22
|
+
when IO
|
23
|
+
[io, io]
|
24
|
+
when Array
|
25
|
+
[io[0], io[1]]
|
26
|
+
else
|
27
|
+
raise ArgumentError, "io must be an instance of IO or Array"
|
28
|
+
end
|
29
|
+
@strict_capabilities = strict_capabilities
|
30
|
+
@closed = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def start
|
34
|
+
begin
|
35
|
+
exchange_hello
|
36
|
+
negotiate_capabilities
|
37
|
+
initialize_sender_and_receiver
|
38
|
+
operation_loop
|
39
|
+
rescue
|
40
|
+
raise
|
41
|
+
ensure
|
42
|
+
close
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
@logger.info { "Being closed" }
|
48
|
+
@closed = true
|
49
|
+
begin
|
50
|
+
@io_r.close_read
|
51
|
+
rescue
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def closed?
|
56
|
+
@closed
|
57
|
+
end
|
58
|
+
|
59
|
+
def exchange_hello
|
60
|
+
send_hello
|
61
|
+
receive_hello
|
62
|
+
end
|
63
|
+
|
64
|
+
def send_hello
|
65
|
+
@logger.info { "Local capabilities: #{@local_capabilities}" }
|
66
|
+
xml_doc = REXML::Document.new
|
67
|
+
hello_e = xml_doc.add_element 'hello'
|
68
|
+
hello_e.add_namespace('urn:ietf:params:xml:ns:netconf:base:1.0')
|
69
|
+
capabilities_e = hello_e.add_element 'capabilities'
|
70
|
+
@local_capabilities.list_loadable.each{ |c|
|
71
|
+
capability_e = capabilities_e.add_element 'capability'
|
72
|
+
capability_e.text = c
|
73
|
+
}
|
74
|
+
session_id_e = hello_e.add_element 'session-id'
|
75
|
+
session_id_e.text = @session_id.to_s
|
76
|
+
|
77
|
+
buf = String.new
|
78
|
+
formatter = REXML::Formatters::Pretty.new(2)
|
79
|
+
formatter.compact = true
|
80
|
+
formatter.write(xml_doc, buf)
|
81
|
+
@logger.debug { "Sending hello message: #{buf.inspect}" }
|
82
|
+
@io_w.write "#{buf}\n]]>]]>\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
def receive_hello
|
86
|
+
buf = String.new
|
87
|
+
loop do
|
88
|
+
buf += @io_r.read(1)
|
89
|
+
if buf[-6..-1] == ']]>]]>'
|
90
|
+
break
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@logger.debug { "Received hello message: #{buf[0..-7].inspect}" }
|
94
|
+
remote_capabilities_xml_doc = REXML::Document.new(buf[0..-7], {:ignore_whitespace_nodes => :all})
|
95
|
+
remote_capabilities_xml_doc.each_element('/hello/capabilities/capability'){ |c| @remote_capabilities.push c.text }
|
96
|
+
@logger.info { "Remote capabilities: #{@remote_capabilities}" }
|
97
|
+
end
|
98
|
+
|
99
|
+
def negotiate_capabilities
|
100
|
+
@capabilities = @local_capabilities.negotiate @remote_capabilities
|
101
|
+
@logger.info { "Negotiated capabilities: #{@capabilities.list_loadable}" }
|
102
|
+
unless @capabilities.list_loadable.any?{ |c| /^urn:ietf:params:netconf:base:\d+\.\d+$/ =~ c }
|
103
|
+
@logger.error { "No base NETCONF capability negotiated" }
|
104
|
+
raise "No base NETCONF capability negotiated"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def initialize_sender_and_receiver
|
109
|
+
base_capability = @capabilities.list_loadable.select{ |c| /^urn:ietf:params:netconf:base:\d+\.\d+$/ =~ c }.sort.last
|
110
|
+
@logger.info { "Base NETCONF capability: #{base_capability}" }
|
111
|
+
@sender = Capability[base_capability]::Sender.new @io_w
|
112
|
+
@receiver = Capability[base_capability]::Receiver.new @io_r
|
113
|
+
end
|
114
|
+
|
115
|
+
def operation_loop
|
116
|
+
datastore_session = @datastore.new_session self
|
117
|
+
operation = Operation.new self, @capabilities, datastore_session, @strict_capabilities
|
118
|
+
|
119
|
+
begin
|
120
|
+
loop do
|
121
|
+
if closed?
|
122
|
+
break
|
123
|
+
end
|
124
|
+
|
125
|
+
begin
|
126
|
+
begin
|
127
|
+
received_message = @receiver.receive_message
|
128
|
+
break unless received_message
|
129
|
+
rpc_reply_e = operation.run received_message
|
130
|
+
rescue Error => e
|
131
|
+
if received_message
|
132
|
+
rpc_reply_e = received_message.clone
|
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
|
138
|
+
rpc_reply_e.add e.to_rpc_error
|
139
|
+
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
|
+
end
|
150
|
+
end
|
151
|
+
ensure
|
152
|
+
begin
|
153
|
+
datastore_session.close
|
154
|
+
rescue
|
155
|
+
end
|
156
|
+
begin
|
157
|
+
@io_w.close_write
|
158
|
+
rescue
|
159
|
+
end
|
160
|
+
end
|
161
|
+
@logger.info { "Exit operation_loop" }
|
162
|
+
end
|
163
|
+
|
164
|
+
def close_other session_id
|
165
|
+
@server.close_session session_id
|
166
|
+
end
|
167
|
+
|
168
|
+
def lock target
|
169
|
+
@server.lock target, @session_id
|
170
|
+
end
|
171
|
+
|
172
|
+
def unlock target
|
173
|
+
@server.unlock target, @session_id
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|