Project

General

Profile

« Previous | Next » 

Revision 8fcaacd6

Added by Marc Dequènes over 13 years ago

  • ID 8fcaacd6b9f666dcfb94138e296b2c320fe9799f

[evol] work on cyborg server protocol and API #7 (refs #31)

View differences:

bin/mapmaker
require 'cyborghood/cyborg'
require 'cyborghood/cyborg/server'
require 'cyborghood/services/dns'
module CyborgHood
......
include CyborgServerInterface
include CyborgServerDefaultInterface
class DNS
class DNS < Services::DNS
include CyborgServerInterface
def zone_exists?(data)
pp data
"coucou"
export_parent_methods
unexport_method :zones
def test(data)
"coucou: " + data.inspect
end
class Zones
include CyborgServerInterface
def initialize
@dns = Services::DNS.new
end
def api_methods
@dns.zones
end
def method_missing(method_name, *args)
if api_methods.include?(method_name.to_s)
Zone.new(method_name.to_s)
else
super
end
end
class Zone < Services::Zone
include CyborgServerEmbededInterface
end
end
end
end
data/cyborghood/default_config/mapmaker.yaml
---
dns: {}
dns:
software: bind
data/cyborghood/schema/mapmaker.yaml
"dns":
type: map
mapping:
"software": {type: str, enum: [bind]}
"master_zone_pattern": {type: str, required: yes, name: MasterZonePattern}
lib/cyborghood/base/lang_additions.rb
def human_name
self.class.human_name
end
def singleton_class
class << self; self; end
end
end
class String
......
Float self rescue false
end
end
lib/cyborghood/cyborg/interface.rb
module CyborgHood
module CyborgServerInterface
def self.included(base)
base.class_eval("include CyborgServerInterfaceBase")
base.class_eval("include Singleton")
end
end
module CyborgServerEmbededInterface
def self.included(base)
base.class_eval("include CyborgServerInterfaceBase")
base.export_parent_methods
end
end
module CyborgServerInterfaceBase
NODE_PATTERN = "([a-zA-Z0-9._]+(?:\/[a-zA-Z0-9._]+)*[?=]?)"
def self.included(base)
base.extend(ClassMethods)
end
......
self.exported_methods ||= []
self.exported_methods += syms.collect{|m| m.to_s }
end
def unexport_method(syms)
syms = [syms] unless syms.is_a? Array
self.exported_methods ||= []
self.exported_methods -= syms.collect{|m| m.to_s }
end
def export_parent_methods
self.export_method self.superclass.public_instance_methods(false)
end
end
def initialize
def initialize(*args)
super(*args)
@config = Config.instance
self.class.exported_methods ||= []
......
def api_klasses
list = self.class.constants.collect do |c|
cc = self.class.const_get(c)
(cc.class == Class and cc.ancestors.include? CyborgServerInterface) ? [c, cc] : nil
(cc.class == Class and cc.ancestors.include? CyborgHood::CyborgServerInterfaceBase) ? [c, cc] : nil
end.compact
Hash[list]
end
......
end
def find_node_action(node_name)
next_node_name, other_nodes_names = node_name.split('.', 2)
next_node_name, other_nodes_names = node_name.split('/', 2)
next_node_klass = api_klasses[next_node_name]
# inner class or method ?
if next_node_klass.nil?
# method is declared ?
if api_methods.include? next_node_name
next_node_method = self.method(next_node_name)
return next_node_method if other_nodes_names.nil?
next_node = next_node_method.call
# final node ?
if other_nodes_names.nil?
# cannot use method(), as this method may not exist at all (but still
# be usuable through metaprogramming
return lambda do |*args|
r = self.send(next_node_name, *args)
# dynamic tree construction: method may return a node
if r.class.ancestors.include? CyborgHood::CyborgServerInterfaceBase
r.api_nodes
else
r
end
end
end
next_node = self.send(next_node_name)
else
# unknown method
return
end
else
next_node = next_node_klass.instance
# final node ?
return next_node.method('api_nodes') if other_nodes_names.nil?
end
next_node.find_node_action(other_nodes_names)
# search deeper
if next_node.class.ancestors.include? CyborgHood::CyborgServerInterfaceBase
next_node.find_node_action(other_nodes_names)
else
# it is not a node, so there are no children
return
end
end
def has_node?(cmd)
lib/cyborghood/cyborg/server.rb
MaxLineLength = 16*1024
EOD = "\033[0J"
NODE_PATTERN = /^([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*[?=]?)(?: ([+?]+))?$/
COMMAND_PATTERN = "^#{CyborgServerInterfaceBase::NODE_PATTERN}(?: ([+?]+))?$"
def initialize(interface)
@interface = interface
......
else
logger.debug "Received data [#{identifier}]: #{data}"
unless data =~ NODE_PATTERN
unless data =~ Regexp.new(COMMAND_PATTERN)
logger.error "Error [#{identifier}]: syntax error"
send_line "552 syntax error in command"
return
end
cmd = $1
flags = $2 || ""
pp "GROK"
pp cmd
pp flags
if flags.index '?'
send_line "250+ ok"
lib/cyborghood/services/dns.rb
require 'fileutils'
# ensure we can find the needed programs (should be handled somewhere else)
ENV['PATH'] = (ENV['PATH'].split(":") + ["/sbin", "/usr/sbin", "/usr/local/sbin"]).uniq.join(":")
module CyborgHood
module Services
class DNS
def initialize
@config = Config.instance
@zone_files_pattern = @config.dns.master_zone_pattern.gsub("#ZONE#", "*")
@zone_files_regex = Regexp.new("^" + @config.dns.master_zone_pattern.gsub("#ZONE#", "(.*)") + "$")
end
def zones(zone = nil)
if zone.nil?
Dir.glob(@zone_files_pattern).collect do |file|
$1 if file =~ @zone_files_regex
end
else
Zone.new(zone)
end
end
end
class Zone
attr_reader :zone
attr_accessor :content
......
@content = nil
@filename = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
# ensure we can find the needed programs (should be handled somewhere else)
ENV['PATH'] = (ENV['PATH'].split(":") + ["/sbin", "/usr/sbin", "/usr/local/sbin"]).uniq.join(":")
end
def read_zone
......
end
def serial
case @config.dns.nameserver || :bind
when :bind
case @config.dns.software
when 'bind'
output = []
begin
IO.popen("named-checkzone -i none '#{@zone}' #{@filename}") do |fp|
output << fp.gets.chomp! until fp.eof?
end
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone serial for '#{@zone}' could not be found")
raise CyberError.new(:unrecoverable, "services/dns", "zone serial for '#{@zone}' could not be found (I/O error)")
end
raise CyberError.new(:unrecoverable, "services/dns", "zone serial for '#{@zone}' could not be found (#{output.first})") unless $?.success?
if $? == 0
serial = nil
......
else
nil
end
else
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: unknown nameserver")
end
end
def check_zone_file(filename)
case @config.dns.nameserver || :bind
when :bind
case @config.dns.software
when 'bind'
output = []
begin
IO.popen("named-checkzone '#{@zone}' #{filename}") do |fp|
......
else
return {:ok => false, :errors => messages}.to_ostruct
end
else
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: unknown nameserver")
end
end

Also available in: Unified diff