knot-ruby 0.1.2 → 0.2.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/Gemfile +1 -0
- data/knot-ruby.gemspec +1 -1
- data/lib/knot/interface.rb +27 -22
- data/lib/knot/protocol.rb +116 -50
- data/lib/knot/version.rb +1 -1
- data/lib/knot.rb +10 -0
- metadata +4 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 431bf7db78b2a1b8e1698f53eec8ae8726ef3aca3a9c3b38c77f06ef592fd9c9
|
4
|
+
data.tar.gz: 8dcf78f6703e9c1c00149f629684b1cda175f20f2148c9780cd4eead1a9e78fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68642c8b64d37524a7ee4b53187e444dfe003fc5e47ee6208954b078c9849fabbfcd5080472a7bd42f2fa9721cac6060a04ff26233ba3ee891698cd4227ff919
|
7
|
+
data.tar.gz: 7bcbe887741d86b4fdc09212ae92a8ffc08e824aaaf9ec82fa225e4faf3a5db9434ab99bfff14cc0e918f24f9df6ea792b074f66c1a58ba7a25f8b12d32c1dfd
|
data/Gemfile
CHANGED
data/knot-ruby.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.summary = %q{Provides interface to knot-server.}
|
11
11
|
spec.description = %q{Implements knot-protocol to provide an interface to knot-DNS-server}
|
12
12
|
spec.homepage = 'https://git.denkn.at/deac/knot'
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
14
14
|
|
15
15
|
#spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
16
16
|
|
data/lib/knot/interface.rb
CHANGED
@@ -69,7 +69,7 @@ class Knot::Zone
|
|
69
69
|
|
70
70
|
def read() @protocol.call command: 'zone-read', zone: @zone end
|
71
71
|
def diff() @protocol.call command: 'zone-diff', zone: @zone end
|
72
|
-
|
72
|
+
|
73
73
|
# setting record
|
74
74
|
# if data is nil, it will be unset.
|
75
75
|
def set owner, ttl = nil, type, data
|
@@ -127,59 +127,64 @@ class Knot::Conf
|
|
127
127
|
self.commit
|
128
128
|
end
|
129
129
|
|
130
|
-
def parse_item
|
131
|
-
case
|
130
|
+
def parse_item kv
|
131
|
+
case kv
|
132
132
|
when Hash
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
r = {}
|
134
|
+
kv.each {|k,v| r[k.to_s.to_sym] = v }
|
135
|
+
case r.keys.sort
|
136
|
+
when %i[section], %i[id section], %i[item section], %i[id item section]
|
137
|
+
r
|
136
138
|
else
|
137
|
-
raise ArgumentError, "Invalid Item-format"
|
139
|
+
raise ArgumentError, "Invalid Item-format: #{k}"
|
138
140
|
end
|
139
141
|
|
140
142
|
when Array
|
141
|
-
case
|
142
|
-
when 1 then {section:
|
143
|
-
when 2 then {section:
|
144
|
-
when 3 then {section:
|
145
|
-
else raise ArgumentError, "Invalid Item-format"
|
143
|
+
case kv.length
|
144
|
+
when 1 then {section: kv[0]}
|
145
|
+
when 2 then {section: kv[0], item: kv[1]}
|
146
|
+
when 3 then {section: kv[0], id: kv[1], item: kv[2]}
|
147
|
+
else raise ArgumentError, "Invalid Item-format: #{kv}"
|
146
148
|
end
|
147
149
|
|
148
150
|
when /\A
|
149
|
-
|
150
|
-
|
151
|
-
|
151
|
+
(?<section> [a-z0-9_-]+ )
|
152
|
+
(?: \[ (?<id> [a-z0-9_.-]+) \] )?
|
153
|
+
(?: \. (?<item>[a-z0-9_-]+) )?
|
152
154
|
\z/xi
|
153
155
|
|
154
|
-
|
156
|
+
$~.named_captures.delete_if {|_,v| v.nil? }
|
157
|
+
|
158
|
+
when nil
|
159
|
+
{}
|
155
160
|
|
156
161
|
else
|
157
|
-
raise ArgumentError, "Invalid Item-format"
|
162
|
+
raise ArgumentError, "Invalid Item-format: #{kv}"
|
158
163
|
end
|
159
164
|
end
|
160
165
|
|
161
166
|
def get item = nil
|
162
|
-
@protocol.call
|
167
|
+
@protocol.call **parse_item( item).update( command: 'conf-get')
|
163
168
|
end
|
164
169
|
|
165
170
|
# Sets or adds a new value to item.
|
166
171
|
# knot knows single-value items like `server.rundir` and multi-value items like `server.listen`.
|
167
172
|
# If you set a single-value, it will replace the old value. On a multi-value, it will add it.
|
168
173
|
def set item, value
|
169
|
-
@protocol.call parse_item( item).update( command: 'conf-set', data: value)
|
174
|
+
@protocol.call **parse_item( item).update( command: 'conf-set', data: value)
|
170
175
|
end
|
171
176
|
|
172
177
|
# Removes value from item. If you provide a value, this value will be removed.
|
173
178
|
def unset item, value = nil
|
174
|
-
@protocol.call parse_item( item).update( command: 'conf-unset', data: value)
|
179
|
+
@protocol.call **parse_item( item).update( command: 'conf-unset', data: value)
|
175
180
|
end
|
176
181
|
alias delete unset
|
177
182
|
|
178
183
|
def list item = nil
|
179
|
-
@protocol.call
|
184
|
+
@protocol.call **parse_item( item).update( command: 'conf-list')
|
180
185
|
end
|
181
186
|
|
182
187
|
def read item = nil
|
183
|
-
@protocol.call
|
188
|
+
@protocol.call **parse_item( item).update( command: 'conf-read')
|
184
189
|
end
|
185
190
|
end
|
data/lib/knot/protocol.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'iounpack'
|
2
|
+
require 'stringio'
|
2
3
|
require_relative 'errors'
|
3
4
|
|
4
5
|
module Knot
|
@@ -51,44 +52,98 @@ module Knot::Protocol::Type
|
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
55
|
+
#class Knot::KnotC
|
56
|
+
# attr_accessor :binary
|
57
|
+
#
|
58
|
+
# def initialize path = nil, binary: nil
|
59
|
+
# @path = path
|
60
|
+
# @binary = binary || 'knotc'
|
61
|
+
# @conf = Knot::Conf.new self
|
62
|
+
# @zones = Hash.new {|h, zone| h[zone] = Knot::Zone.new zone, self }
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# def call command:, flags: nil, section: nil, item: nil, id: nil, zone: nil, owner: nil, ttl: nil, type: nil, data: nil, filter: nil
|
66
|
+
# cs =
|
67
|
+
# case command.to_s
|
68
|
+
# when 'conf-begin', 'conf-commit', 'conf-abort', 'status', 'stop', 'reload'
|
69
|
+
# [@binary, command, ]
|
70
|
+
# else raise ArgumentError, "Unknown Command: #{command}"
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
#end
|
74
|
+
|
54
75
|
module Knot::Protocol::Idx
|
76
|
+
class Id
|
77
|
+
include Comparable
|
78
|
+
attr_reader :name, :code, :cname, :description
|
79
|
+
|
80
|
+
def initialize name, code, cname, description
|
81
|
+
raise ArgumentError, "Expecting Symbol for #{self.class.name} instead of: #{name.inspect}" unless Symbol === name
|
82
|
+
raise ArgumentError, "Expecting Integer for #{self.class.name} instead of: #{code.inspect}" unless Integer === code
|
83
|
+
@name, @code, @cname, @description = name, code, cname, description
|
84
|
+
freeze
|
85
|
+
end
|
86
|
+
|
87
|
+
def === x
|
88
|
+
case x
|
89
|
+
when self.class then self == x
|
90
|
+
when Symbol then @name == x
|
91
|
+
when String then @name == x.to_sym
|
92
|
+
when Integer then @code == x
|
93
|
+
else nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def <=>( x) @id <=> x.id end
|
98
|
+
def to_s() @name.to_s end
|
99
|
+
def to_sym() @name end
|
100
|
+
def to_i() @code end
|
101
|
+
end
|
102
|
+
|
55
103
|
Idx = [
|
56
|
-
:command,
|
57
|
-
:flags,
|
58
|
-
:error,
|
59
|
-
:section,
|
60
|
-
:item,
|
61
|
-
:id,
|
62
|
-
:zone,
|
63
|
-
:owner,
|
64
|
-
:ttl,
|
65
|
-
:type,
|
66
|
-
:data,
|
67
|
-
:filter,
|
104
|
+
Id.new( :command, 0x10, :CMD, 'Control command name.'),
|
105
|
+
Id.new( :flags, 0x11, :FLAGS, 'Control command flags.'),
|
106
|
+
Id.new( :error, 0x12, :ERROR, 'Error message.'),
|
107
|
+
Id.new( :section, 0x13, :SECTION, 'Configuration section name.'),
|
108
|
+
Id.new( :item, 0x14, :ITEM, 'Configuration item name.'),
|
109
|
+
Id.new( :id, 0x15, :ID, 'Congiguration item identifier.'),
|
110
|
+
Id.new( :zone, 0x16, :ZONE, 'Zone name.'),
|
111
|
+
Id.new( :owner, 0x17, :OWNER, 'Zone record owner'),
|
112
|
+
Id.new( :ttl, 0x18, :TTL, 'Zone record TTL.'),
|
113
|
+
Id.new( :type, 0x19, :TYPE, 'Zone record type name.'),
|
114
|
+
Id.new( :data, 0x1a, :DATA, 'Configuration item/zone record data.'),
|
115
|
+
Id.new( :filter, 0x1b, :FILTER, 'An option or a filter for output data processing.'),
|
68
116
|
]
|
69
117
|
Name = {}
|
70
118
|
Code = {}
|
71
|
-
|
72
|
-
|
73
|
-
|
119
|
+
|
120
|
+
Idx.each do |id|
|
121
|
+
Code[id.to_i] = id
|
122
|
+
Name[id.to_sym] = id
|
74
123
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
124
|
+
|
125
|
+
class <<self
|
126
|
+
def [] k
|
127
|
+
case k
|
128
|
+
when Symbol
|
129
|
+
Name[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
|
130
|
+
when Integer
|
131
|
+
Code[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
|
132
|
+
else
|
133
|
+
raise ArgumentError, "Unknown Idx-Type: #{k}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def each &exe
|
138
|
+
block_given? ? Idx.each( &exe) : Idx.to_enum( :each)
|
83
139
|
end
|
84
140
|
end
|
85
141
|
end
|
86
142
|
|
87
143
|
class Knot::Protocol
|
88
|
-
attr_reader :sock, :conf, :zones
|
89
|
-
attr_accessor :debug
|
144
|
+
attr_reader :sock, :conf, :zones, :logger
|
90
145
|
|
91
|
-
def initialize path_or_sock = nil
|
146
|
+
def initialize path_or_sock = nil, logger: nil
|
92
147
|
case path_or_sock
|
93
148
|
when String, Pathname
|
94
149
|
@sock = UNIXSocket.new path_or_sock.to_s
|
@@ -97,54 +152,62 @@ class Knot::Protocol
|
|
97
152
|
when nil
|
98
153
|
@sock = UNIXSocket.new '/run/knot/knot.sock'
|
99
154
|
end
|
100
|
-
@
|
155
|
+
@logger = logger || Logger.new(STDERR)
|
101
156
|
@conf = Knot::Conf.new self
|
102
157
|
@zones = Hash.new {|h, zone| h[zone] = Knot::Zone.new zone, self }
|
103
158
|
end
|
104
159
|
|
105
160
|
def snd sock: nil, **data
|
106
161
|
rsock = sock || @sock
|
107
|
-
s = ''
|
108
|
-
sock = StringIO.new s
|
109
|
-
sock.write [1].pack( 'c')
|
162
|
+
#s = ''.b
|
163
|
+
#sock = StringIO.new s
|
164
|
+
#sock.write [1].pack( 'c')
|
110
165
|
data[:flags] ||= ''
|
111
|
-
|
112
|
-
|
113
|
-
|
166
|
+
ds =
|
167
|
+
Idx::Idx.
|
168
|
+
select {|n| data[n.to_sym] }.
|
169
|
+
map {|n| v = data[n.to_sym].to_s.b; [n.to_i, v.size, v ] }
|
170
|
+
s = (ds.flatten+[3]).pack( ('c na*'*ds.length)+'c').b
|
171
|
+
#Idx::Idx.each do |n|
|
172
|
+
# v = data[n.to_sym]&.to_s&.b
|
173
|
+
# sock.write [n.to_i, v.size, v].pack( 'c na*') if v
|
174
|
+
#end
|
175
|
+
#sock.write [3].pack( 'c')
|
176
|
+
#sock.flush
|
177
|
+
if 0 >= @logger.sev_threshold
|
178
|
+
@logger.debug "send data #{data.inspect}"
|
179
|
+
@logger.debug "send raw #{s.inspect}"
|
114
180
|
end
|
115
|
-
sock.write [3].pack( 'c')
|
116
|
-
sock.flush
|
117
|
-
STDERR.puts( {data: data, _: s}.inspect) if @debug
|
118
181
|
rsock.write s
|
119
182
|
rsock.flush
|
120
|
-
end
|
183
|
+
end
|
121
184
|
|
122
185
|
class RecordIO
|
123
186
|
attr_reader :str
|
124
187
|
|
125
188
|
def initialize sock, str = nil
|
126
|
-
@str, @sock = str || '', sock
|
189
|
+
@str, @sock = str || ''.b, sock
|
127
190
|
end
|
128
191
|
|
129
192
|
def unpack pattern
|
130
|
-
IOUnpack.new(pattern).unpack self
|
193
|
+
IOUnpack.new( pattern).unpack self
|
131
194
|
end
|
132
195
|
|
133
196
|
def unpack1 pattern
|
134
|
-
IOUnpack.new(pattern).unpack1 self
|
197
|
+
IOUnpack.new( pattern).unpack1 self
|
135
198
|
end
|
136
199
|
|
137
200
|
def read n
|
138
201
|
s = @sock.read n
|
139
|
-
@str.insert -1, s
|
140
|
-
s
|
202
|
+
@str.insert -1, s unless s.nil?
|
203
|
+
s || ''
|
141
204
|
end
|
142
205
|
end
|
143
206
|
|
144
207
|
def rcv sock: nil
|
145
208
|
ret, r = [], nil
|
146
209
|
sock = sock || @sock
|
147
|
-
sock = RecordIO.new sock if @
|
210
|
+
sock = RecordIO.new sock if 0 >= @logger.sev_threshold
|
148
211
|
loop do
|
149
212
|
t = sock.unpack1 'c'
|
150
213
|
case t
|
@@ -153,7 +216,7 @@ class Knot::Protocol
|
|
153
216
|
when 1, 2
|
154
217
|
type = t
|
155
218
|
ret.push( r = {})
|
156
|
-
else
|
219
|
+
else
|
157
220
|
raise Knot::Errors::EINVAL, "Missing Type before: #{t}" if ret.empty?
|
158
221
|
i = Idx::Idx[t - 0x10] or raise Knot::Errors::EINVAL, "Unknown index: #{t-0x10}"
|
159
222
|
l = sock.unpack1 'n'
|
@@ -161,13 +224,16 @@ class Knot::Protocol
|
|
161
224
|
end
|
162
225
|
end
|
163
226
|
ensure
|
164
|
-
|
227
|
+
if RecordIO === sock
|
228
|
+
@logger.debug "rcvd raw #{sock.str.inspect}"
|
229
|
+
@logger.debug "rcvd data #{ret.inspect}"
|
230
|
+
end
|
165
231
|
ret
|
166
232
|
end
|
167
233
|
|
168
234
|
def call sock: nil, **data
|
169
235
|
snd sock: sock, **data
|
170
|
-
rcv( sock: sock).each do |r|
|
236
|
+
rcv( sock: sock).each do |r|
|
171
237
|
if r[:error]
|
172
238
|
if e = Knot::Errors.err2exc[r[:error]]
|
173
239
|
raise e, r[:error]
|
@@ -179,10 +245,10 @@ class Knot::Protocol
|
|
179
245
|
|
180
246
|
def zone( zone) @zones[zone.to_s.to_sym] end
|
181
247
|
|
182
|
-
def conf_set( **opts) call **opts.update( command: 'conf-set')
|
183
|
-
def conf_unset( **opts) call **opts.update( command: 'conf-
|
248
|
+
def conf_set( **opts) call **opts.update( command: 'conf-set') end
|
249
|
+
def conf_unset( **opts) call **opts.update( command: 'conf-unset') end
|
184
250
|
|
185
|
-
def zone_set( **opts) call **opts.update( command: 'zone-set')
|
251
|
+
def zone_set( **opts) call **opts.update( command: 'zone-set') end
|
186
252
|
def zone_unset( **opts) call **opts.update( command: 'zone-unset') end
|
187
|
-
def zone_get( **opts) call **opts.update( command: 'zone-get')
|
253
|
+
def zone_get( **opts) call **opts.update( command: 'zone-get') end
|
188
254
|
end
|
data/lib/knot/version.rb
CHANGED
data/lib/knot.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knot-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Knauf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: iounpack
|
@@ -57,15 +57,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 2.
|
60
|
+
version: 2.7.0
|
61
61
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
62
|
requirements:
|
63
63
|
- - ">="
|
64
64
|
- !ruby/object:Gem::Version
|
65
65
|
version: '0'
|
66
66
|
requirements: []
|
67
|
-
|
68
|
-
rubygems_version: 2.7.6.2
|
67
|
+
rubygems_version: 3.2.5
|
69
68
|
signing_key:
|
70
69
|
specification_version: 4
|
71
70
|
summary: Provides interface to knot-server.
|