2020-06-20 22:30:05 +02:00
|
|
|
require_relative 'protocol'
|
|
|
|
require_relative 'errors'
|
|
|
|
|
|
|
|
module Knot
|
|
|
|
end
|
|
|
|
|
|
|
|
class Knot::Zone
|
|
|
|
attr_reader :protocol, :zone
|
|
|
|
def initialize zone, protocol = nil
|
|
|
|
@protocol = protocol || Protocol.new
|
|
|
|
@zone, @transaction_opened = zone, 0
|
|
|
|
end
|
|
|
|
|
2020-12-02 16:20:58 +01:00
|
|
|
# If no transaction opened, yet, it opens a new transaction.
|
|
|
|
# Counts calling begin.
|
|
|
|
# Knot allowes only one global transaction, so if two clients tries to open a transaction,
|
|
|
|
# the second will fail. But the second client can change items in the same
|
|
|
|
# transaction like the first client.
|
|
|
|
# The first client, which calls commit or abort, wins and the transaction will be closed.
|
|
|
|
# So, the transaction-handling is only safe, if one client connects to knot.
|
2020-06-20 22:30:05 +02:00
|
|
|
def begin
|
|
|
|
@transaction_opened += 1
|
|
|
|
@protocol.call command: 'zone-begin', zone: @zone if 1 == @transaction_opened
|
|
|
|
end
|
|
|
|
|
2020-12-02 16:20:58 +01:00
|
|
|
# Decreases opened transactions.
|
|
|
|
# If opened transactions is zero, it stores items and closes transaction successfully.
|
2020-06-20 22:30:05 +02:00
|
|
|
def commit
|
|
|
|
@protocol.call command: 'zone-commit', zone: @zone if 1 == @transaction_opened
|
|
|
|
@transaction_opened -= 1 if 0 < @transaction_opened
|
|
|
|
end
|
|
|
|
|
2020-12-02 16:20:58 +01:00
|
|
|
# Closes transaction without saving immidiatly.
|
|
|
|
# Counter of opened transaction will be reset to 0.
|
2020-06-20 22:30:05 +02:00
|
|
|
def abort
|
|
|
|
@protocol.call command: 'zone-abort', zone: @zone
|
|
|
|
@transaction_opened = 0
|
|
|
|
end
|
|
|
|
|
2020-12-02 16:20:58 +01:00
|
|
|
# Opens transaction, calls yielded Proc and closes transaction after return.
|
|
|
|
# If exception was raised, the transaction will be aborted.
|
|
|
|
def transaction # :yield:
|
2020-06-20 22:30:05 +02:00
|
|
|
self.begin
|
|
|
|
yield self
|
|
|
|
rescue Object
|
|
|
|
self.abort
|
|
|
|
raise
|
|
|
|
ensure
|
|
|
|
self.commit unless $!
|
|
|
|
end
|
|
|
|
|
|
|
|
# zone operation
|
|
|
|
|
|
|
|
def check() @protocol.call command: 'zone-check', zone: @zone end
|
|
|
|
def reload() @protocol.call command: 'zone-reload', zone: @zone end
|
|
|
|
def refresh() @protocol.call command: 'zone-refresh', zone: @zone end
|
|
|
|
def notify() @protocol.call command: 'zone-notify', zone: @zone end
|
|
|
|
def retransfer() @protocol.call command: 'zone-retransfer', zone: @zone end
|
|
|
|
def sign() @protocol.call command: 'zone-sign', zone: @zone end
|
|
|
|
def freeze() @protocol.call command: 'zone-freeze', zone: @zone end
|
|
|
|
def thaw() @protocol.call command: 'zone-thaw', zone: @zone end
|
|
|
|
def status( filter = nil) @protocol.call command: 'zone-status', zone: @zone, filter: filter end
|
|
|
|
|
|
|
|
def stats( modul = nil, counter = nil)
|
|
|
|
@protocol.call command: 'zone-stats', zone: @zone, module: modul, counter: counter
|
|
|
|
end
|
|
|
|
|
|
|
|
# zone manipulation
|
|
|
|
|
|
|
|
def read() @protocol.call command: 'zone-read', zone: @zone end
|
|
|
|
def diff() @protocol.call command: 'zone-diff', zone: @zone end
|
2022-09-27 20:58:19 +02:00
|
|
|
|
2020-06-20 22:30:05 +02:00
|
|
|
# setting record
|
|
|
|
# if data is nil, it will be unset.
|
|
|
|
def set owner, ttl = nil, type, data
|
|
|
|
@protocol.call command: data.nil? ? 'zone-unset' : 'zone-set',
|
|
|
|
zone: @zone, owner: owner, ttl: ttl, type: type, data: data
|
|
|
|
rescue Knot::Errors::EISRECORD, Knot::Errors::ENONODE, Knot::Errors::ENOENT
|
|
|
|
end
|
|
|
|
alias []= set
|
|
|
|
|
|
|
|
def unset owner, type = nil, data = nil
|
|
|
|
@protocol.call command: 'zone-unset',
|
|
|
|
zone: @zone, owner: owner, type: type, data: data
|
|
|
|
rescue Knot::Errors::ENONODE, Knot::Errors::ENOENT
|
|
|
|
end
|
|
|
|
alias delete unset
|
2020-12-02 16:20:58 +01:00
|
|
|
alias del unset
|
2020-06-20 22:30:05 +02:00
|
|
|
|
|
|
|
def get owner = nil, type = nil
|
|
|
|
@protocol.call command: 'zone-get',
|
|
|
|
zone: @zone, owner: owner, type: type
|
|
|
|
rescue Knot::Errors::ENONODE, Knot::Errors::ENOENT
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
alias [] get
|
|
|
|
end
|
|
|
|
|
|
|
|
class Knot::Conf
|
|
|
|
def initialize protocol = nil
|
|
|
|
@protocol = protocol || Protocol.new
|
|
|
|
@transaction_opened = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
def begin
|
|
|
|
@transaction_opened += 1
|
|
|
|
@protocol.call command: 'conf-begin' if 1 == @transaction_opened
|
|
|
|
end
|
|
|
|
|
|
|
|
def commit
|
|
|
|
@protocol.call command: 'conf-commit' if 1 == @transaction_opened
|
|
|
|
@transaction_opened -= 1 if 0 < @transaction_opened
|
|
|
|
end
|
|
|
|
|
|
|
|
def abort
|
|
|
|
@protocol.call command: 'conf-abort'
|
|
|
|
@transaction_opened = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
def transaction
|
|
|
|
self.begin
|
|
|
|
yield self
|
|
|
|
rescue Object
|
|
|
|
self.abort
|
|
|
|
raise
|
|
|
|
ensure
|
|
|
|
self.commit
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse_item k
|
|
|
|
case k
|
2020-12-02 16:20:58 +01:00
|
|
|
when Hash
|
2020-06-20 22:30:05 +02:00
|
|
|
case k.keys.sort
|
2020-12-02 16:20:58 +01:00
|
|
|
when %w[section], %w[id section], %w[item section], %w[id item section]
|
|
|
|
k
|
|
|
|
else
|
|
|
|
raise ArgumentError, "Invalid Item-format"
|
2020-06-20 22:30:05 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
when Array
|
|
|
|
case k.length
|
|
|
|
when 1 then {section: k[0]}
|
|
|
|
when 2 then {section: k[0], item: k[1]}
|
|
|
|
when 3 then {section: k[0], id: k[1], item: k[2]}
|
|
|
|
else raise ArgumentError, "Invalid Item-format"
|
|
|
|
end
|
|
|
|
|
|
|
|
when /\A
|
|
|
|
(?<section> [a-z0-9_-]+ )
|
|
|
|
(?: \[ (?<id> [a-z0-9_.-]+) \] )?
|
|
|
|
(?: \. (?<item>[a-z0-9_-]+) )?
|
|
|
|
\z/xi
|
2020-12-02 16:20:58 +01:00
|
|
|
|
2020-06-20 22:30:05 +02:00
|
|
|
$~.named_captures.delete_if {|_,v| v.nil? }
|
2020-12-02 16:20:58 +01:00
|
|
|
|
2022-09-27 20:58:19 +02:00
|
|
|
when nil
|
|
|
|
{}
|
|
|
|
|
2020-12-02 16:20:58 +01:00
|
|
|
else
|
|
|
|
raise ArgumentError, "Invalid Item-format"
|
2020-06-20 22:30:05 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-12-02 16:20:58 +01:00
|
|
|
def get item = nil
|
2022-09-27 20:58:19 +02:00
|
|
|
@protocol.call **parse_item( item).update( command: 'conf-get')
|
2020-12-02 16:20:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Sets or adds a new value to item.
|
|
|
|
# knot knows single-value items like `server.rundir` and multi-value items like `server.listen`.
|
|
|
|
# If you set a single-value, it will replace the old value. On a multi-value, it will add it.
|
2020-06-20 22:30:05 +02:00
|
|
|
def set item, value
|
2022-09-27 20:58:19 +02:00
|
|
|
@protocol.call **parse_item( item).update( command: 'conf-set', data: value)
|
2020-06-20 22:30:05 +02:00
|
|
|
end
|
|
|
|
|
2020-12-02 16:20:58 +01:00
|
|
|
# Removes value from item. If you provide a value, this value will be removed.
|
2020-06-20 22:30:05 +02:00
|
|
|
def unset item, value = nil
|
2022-09-27 20:58:19 +02:00
|
|
|
@protocol.call **parse_item( item).update( command: 'conf-unset', data: value)
|
2020-06-20 22:30:05 +02:00
|
|
|
end
|
|
|
|
alias delete unset
|
|
|
|
|
|
|
|
def list item = nil
|
2022-09-27 20:58:19 +02:00
|
|
|
@protocol.call **parse_item( item).update( command: 'conf-list')
|
2020-06-20 22:30:05 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def read item = nil
|
2022-09-27 20:58:19 +02:00
|
|
|
@protocol.call **parse_item( item).update( command: 'conf-read')
|
2020-06-20 22:30:05 +02:00
|
|
|
end
|
|
|
|
end
|