commit 7466fc083799a22deae3d56779823c810028f280
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Mon Nov 29 00:49:24 2010 +0100

    [evol] server API tree reworked using a DSL (reply handling rework is WIP)

diff --git a/bin/librarian b/bin/librarian
index 5bce78a..b057150 100755
--- a/bin/librarian
+++ b/bin/librarian
@@ -35,23 +35,20 @@ module CyborgHood
 
       include BotNet
 
-      def interface
-        LibrarianInterface.instance
-      end
-    end
-
-    class LibrarianInterface
-      include CyborgServerInterface
-      include CyborgServerRootInterfaceAddon
+      def setup
+        super
 
-      class Gruik
-        include CyborgServerInterface
-
-        def api_methods
-          ["g1", "g2", "g3"]
+        define_interface "0.1~" do
+          node "Gruik" do
+            node ["g1", "g2", "g3"] do
+              on_request do |request|
+                request.reply.results = {
+                  :plouf => ">>> #{node_name} <<<"
+                }
+              end
+            end
+          end
         end
-
-        dynamic_interface {|node_name| ">>> #{node_name} <<<" }
       end
     end
   end
diff --git a/bin/mapmaker b/bin/mapmaker
index 394239e..c846142 100755
--- a/bin/mapmaker
+++ b/bin/mapmaker
@@ -31,7 +31,7 @@ module CyborgHood
     class MapMakerValidator < CyborgHoodValidator
       def validate_hook_in(value, rule, path, msg_list)
         case rule.name
-        when 'MasterZonePattern'
+        when 'MasterZonePattern', 'SignedMasterZonePattern', 'SlaveZonePattern'
           if value.gsub('#ZONE#', 'test') == value
             msg_list << "pattern is constant"
           end
@@ -50,58 +50,79 @@ module CyborgHood
 
       include BotNet
 
-      def interface
-        MapMakerInterface.instance
-      end
-    end
-
-    class MapMakerInterface
-      include CyborgServerInterface
-      include CyborgServerRootInterfaceAddon
-
-      class Taiste
-        include CyborgServerInterface
-
-        def api_methods
-          ["coucou", "toto", "plop"]
-        end
-
-        dynamic_interface {|node_name| ">>> #{node_name} <<<" }
-      end
-
-      class DNS < Services::DNS::System
-        include CyborgServerInterface
-
-        export_parent_methods
-        unexport_method :zones, :'[]'
-
-        def test(data)
-          "coucou: " + data.inspect
-        end
-
-        class Zones
-          include CyborgServerStatefulInterface
-
-          def initialize
-            @dns = Services::DNS::System.new
-          end
-
-          def api_methods
-            @dns.zones
-          end
-
-          def api_container_methods
-            api_methods
+      def setup
+        super
+
+        define_interface "0.1~" do
+          node "DNS" do
+            dns = Services::DNS::System.new
+            on_request do |request|
+              request.reply.results = {
+                :type => dns.type
+              }
+            end
+            node "check_config" do
+              on_request do |request|
+                request.reply.results = dns.check_config
+              end
+            end
+            node "Zones" do
+              zone_list = Proc.new{dns.zones}
+              node zone_list do
+                zone = Services::DNS::Zone.new(node_name)
+                on_request do |request|
+                  request.reply.results = {
+                    :master => zone.master?,
+                    :signed => zone.signed?,
+                    :serial => zone.serial_in_dns
+                  }
+                  if zone.master?
+                  reply.results.merge!({
+                      :serial_in_zone_file => zone.serial_in_zone_file,
+                      :serial_in_signed_zone_file => zone.serial_in_signed_zone_file
+                    })
+                  end
+                end
+                node "content" do
+                  on_request do |request|
+                    request.reply.results = {:content => zone.content}
+                  end
+                end
+                node "content=" do
+                  on_request do |request|
+                    content = request.args.shift
+                    if content.nil?
+                      request.errors << "Zone content missing"
+                    end
+
+                    zone.content = content
+                    if zone.changed?
+                      check_result = zone.check
+                      if check_result[:ok]
+                        reply.warnings = check_result[:warnings]
+                        # zone signer automatically handles serial bump
+                        if check_result[:serial] > zone.serial or zone.signed?
+                          zone.save
+                          zone.activate
+                        else
+                          reply.errors << _("Zone serial is not superior to current serial.")
+                        end
+                      else
+                        reply.errors = check_result[:errors]
+                        zone.cancel_changes
+                      end
+                    else
+                      reply.warnings << _("Zone is unmodified (same content)")
+                      zone.cancel_changes
+                    end
+                  end
+                end
+              end
+            end
           end
-
-          stateful_dynamic_interface("DnsZone/#NODE#") {|node_name| DnsZone.new(node_name) }
-        end
+        end # interface
       end
-    end
-
-    class DnsZone < Services::DNS::Zone
-      include CyborgServerEmbeddedInterface
-    end
+    end # class MapMaker
   end
 end
 
diff --git a/bin/test_client b/bin/test_client
index 47a404c..8357dd0 100755
--- a/bin/test_client
+++ b/bin/test_client
@@ -40,8 +40,8 @@ module CyborgHood
         toto = true
 
         task "compare stuff" do
-          ask "MapMaker", :ver1, "/api_version"
-          ask "Librarian", :ver2, "/api_version"
+          ask "MapMaker", :info1, "/_cyborg_"
+          ask "Librarian", :info2, "/_cyborg_"
           ask "MapMaker", :zones, "/DNS/Zones"
           on_error do
             puts "PLOUF"
@@ -52,68 +52,25 @@ module CyborgHood
             puts "OK"
             pp errors
             pp results
-            puts "Tadam: " + (results[:ver1] == results[:ver2] ? "same" : "different")
+            puts "Tadam: " + (results[:info1][:api_version] == results[:info2][:api_version] ? "same" : "different")
             meet "waiter", :zzz
             STDOUT.flush
             on_success do
               puts "OK compare stuff"
             end
           end
+          on_error do
+            stop_bot :at_once
+          end
         end
 
         task "waiter" do
           meet "compare stuff", :zzz
           on_success do
             puts "OK waiter"
-            #stop_bot :at_once
             stop_bot :when_finished
           end
         end
-
-        # conversation_with "MapMaker" do
-        #   on_error do
-        #     puts "Halalalala !"
-        #   end
-        #   thread "super taiste" do
-        #     call :ver, "/api_version"
-        #     call :zones, "/DNS/Zones" if toto
-        #     on_error do
-        #       puts "Sniff !"
-        #       pp reply
-        #     end
-        #     on_success do
-        #       puts "Yahou !"
-        #       pp reply
-        #       call :gogogo, "/DNS"
-        #       on_error do
-        #         pp "Plouf"
-        #         pp reply
-        #       end
-        #       on_success do
-        #         pp "Hop!"
-        #         pp reply
-        #         send_notification 'meetpoint', { :topic => "MYNOTIF", :msg => "plop" }
-        #       end
-        #     end
-        #   end
-        #   #stop_bot :at_once
-        #   stop_bot :when_finished
-        # end
-
-        # conversation_with "Librarian" do
-        #   thread "taistouille" do
-        #     call :sdf, "/Gruik"
-        #     on_success do
-        #       puts "Librarian GoGoGo!"
-        #       pp reply
-        #       wait_notification 'meetpoint', { :topic => "MYNOTIF" }
-        #       on_success do
-        #         puts "NOTIF!"
-        #         pp reply
-        #       end
-        #     end
-        #   end
-        # end
       end
     end
   end
diff --git a/data/cyborghood/schema/mapmaker.yaml b/data/cyborghood/schema/mapmaker.yaml
index ba79ebb..61f7b49 100644
--- a/data/cyborghood/schema/mapmaker.yaml
+++ b/data/cyborghood/schema/mapmaker.yaml
@@ -6,4 +6,6 @@ mapping:
     mapping:
       "software": {type: str, enum: [bind]}
       "master_zone_pattern": {type: str, required: yes, name: MasterZonePattern}
+      "signed_master_zone_pattern": {type: str, name: MasterZonePattern}
+      "slave_zone_pattern": {type: str, required: yes, name: MasterZonePattern}
       "update_zone_script": {type: str}
diff --git a/lib/cyborghood/cyborg/botnet.rb b/lib/cyborghood/cyborg/botnet.rb
index 65a065d..076a18a 100644
--- a/lib/cyborghood/cyborg/botnet.rb
+++ b/lib/cyborghood/cyborg/botnet.rb
@@ -22,13 +22,6 @@ require 'cyborghood/cyborg/botnet/dsl'
 require 'set'
 
 module CyborgHood
-  # default interface if not overridden
-  # a mere "BotClient" would then always have a default basic interface
-  class EmptyInterface
-    include CyborgServerInterface
-    include CyborgServerRootInterfaceAddon
-  end
-
   module BotNet
     attr_reader :interface
 
@@ -47,7 +40,24 @@ module CyborgHood
       @comm_list = {}
       @comm_list_attempt = {}
 
-      self.interface.bot = self
+      # default empty interface
+      define_interface("0") {}
+    end
+
+    def define_interface(version, &block)
+      @interface = DSL::ServerApiNode.new(self, &block)
+      @interface.add_behavior do
+        node "_cyborg_" do
+          on_request do |request|
+            request.reply.results = {
+              :name             => bot.name,
+              :product_name     => PRODUCT,
+              :product_version  => VERSION,
+              :api_version      => version
+            }
+          end
+        end
+      end
     end
 
     def contact_peer(peer, block)
@@ -94,10 +104,6 @@ module CyborgHood
       super
     end
 
-    def interface
-      EmptyInterface.instance
-    end
-
     protected
 
     def process_system_notification(msg)
diff --git a/lib/cyborghood/cyborg/botnet/interface.rb b/lib/cyborghood/cyborg/botnet/interface.rb
index a15a671..f89913f 100644
--- a/lib/cyborghood/cyborg/botnet/interface.rb
+++ b/lib/cyborghood/cyborg/botnet/interface.rb
@@ -17,255 +17,165 @@
 #++
 
 require 'singleton'
+require 'ostruct'
 
 
 module CyborgHood
-  # the base mixin (not intended to be used directly, but...)
-  module CyborgServerInterfaceBase
-    NODE_PATTERN = "((?:\/|(?:\/[a-zA-Z0-9._]+)+[?=]?))"
+  module DSL
+    class ServerApiNode < BaseDSL
+      attr_reader :bot
 
-    attr_accessor :bot
+      # needed for testing node existence
+      reveal :nil?
 
-    def self.included(base)
-      base.extend(ClassMethods)
-    end
-
-    module ClassMethods
-      attr_accessor :exported_methods
-      attr_accessor :auto_export_public_instance_methods
+      def initialize(bot, parent_node = nil, &block)
+        @bot = bot
+        @parent_node = parent_node
+        # don't call super because we need defered loading
+        @blocks = [block]
 
-      def export_method(*syms)
-        syms = [syms] unless syms.is_a? Array
-        self.exported_methods ||= []
-        self.exported_methods += syms.collect{|m| m.to_s }
+        cleanup
       end
 
-      def unexport_method(*syms)
-        syms = [syms] unless syms.is_a? Array
-        self.exported_methods ||= []
-        self.exported_methods -= syms.collect{|m| m.to_s }
+      def add_behavior(&block)
+        @blocks << block
       end
 
-      def export_parent_methods
-        self.export_method *self.superclass.public_instance_methods(false)
+      # string, array (useful for aliases), or regex
+      # TODO: name validation
+      def node(match, &block)
+        child_node = self.class.new(@bot, self, &block)
+        if match.is_a? Array
+          match.each{|n| @nodes[n] = child_node}
+        else
+          @nodes[match] = child_node
+        end
       end
 
-      def is_node?(node)
-        (node =~ Regexp.new(NODE_PATTERN)) ? true : false
+      def on_request(&cb)
+        @request_cb = cb
       end
-    end
-
-    def initialize(*args)
-      super(*args)
-
-      @config = Config.instance
-
-      self.class.exported_methods ||= []
-      self.class.auto_export_public_instance_methods = true
-    end
 
-    # convenience method
-    def is_node?(node)
-      self.class.is_node?(node)
-    end
+      def _is_node?(session, node_path)
+        node = __send__(:find_node, session, node_path)
+        not node.nil?
+      end
 
-    def api_klasses
-      list = self.class.constants.collect do |c|
-        cc = self.class.const_get(c)
-        (cc.class == Class and cc.ancestors.include? CyborgHood::CyborgServerInterfaceBase) ? [c, cc] : nil
-      end.compact
-      Hash[list]
-    end
+      def _call(session, node_path, args = nil)
+        args ||= []
+        raise CyberError.new(:unrecoverable, 'api/cyborghood', "wrong format for arguments") unless args.is_a? Array
 
-    def api_methods
-      methods = []
-      methods += self.class.public_instance_methods(false) if self.class.auto_export_public_instance_methods
-      methods -= ["initialize", "__destroy", "method_missing"]
-      methods &= self.methods
-      methods += self.class.exported_methods
-    end
+        node = find_node(session, node_path)
+        raise CyberError.new(:unrecoverable, 'api/cyborghood', "unknown node") if node.nil?
 
-    def api_container_methods
-      []
-    end
+        logger.debug "[Server API] Node '#{node_path}' found"
+        r = node.__send__(:request, session, args)
+        logger.debug "[Server API] reply for node '#{node_path}': " + r.inspect
+        r
+      end
 
-    def api_containers
-      (api_klasses.keys + api_container_methods).sort
-    end
+      protected
 
-    def api_leafs
-      (api_methods - api_container_methods).sort
-    end
+      def root?
+        @parent_node.nil?
+      end
 
-    def api_nodes
-      (api_klasses.keys + api_methods).sort
-    end
+      def load(node_element = '')
+        cleanup
+        @node_name = node_element
+        @blocks.each do |bl|
+          instance_eval &bl
+        end
+      end
 
-    def find_node_action(session, node_name)
-      node_name.gsub!(/^\//, "")
-      next_node_name, other_nodes_names = node_name.split('/', 2)
+      def find_node(session, node_path)
+        # it is a string argument when interface root is called, but a list of node elemnts later
+        if root?
+          logger.debug "[Server API] Looking for node '#{node_path}'"
+          node_path = node_path.split("/")
+          # remove empty string before first "/"
+          node_path.shift
+          # initial load
+          load
+        end
 
-      next_node_klass = next_node_name.nil? ? self.class : api_klasses[next_node_name]
-      # inner class or method ?
-      if next_node_klass.nil?
-        # method is declared ?
-        if api_methods.include? next_node_name
-          # final node ?
-          if other_nodes_names.blank?
-            # cannot use method(), as this method may not exist at all (but still
-            # be usuable through metaprogramming
-            return lambda do |*args|
-              r = child_node(next_node_name, session, *args)
-              # dynamic tree construction: method may return a node
-              if r.is_a? CyborgHood::CyborgServerInterfaceBase
-                r.api_nodes
-              else
-                r
-              end
-            end
-          end
-          # not a container, leaving
-          return unless self.api_container_methods.include? next_node_name
-          next_node = child_node(next_node_name, session)
+        node_element = node_path.shift
+        logger.debug "[Server API] Looking for node element '#{node_element}'"
+        if node_element.nil?
+          return self
         else
-          # unknown method
-          return
+          next_node = find_child_node(node_element)
+          if next_node
+            next_node.__send__(:load, node_element)
+            return next_node.__send__(:find_node, session, node_path)
+          else
+            return
+          end
         end
-      else
-        next_node = next_node_klass.instance
-        # final node ?
-        return next_node.method('api_nodes') if other_nodes_names.blank?
       end
 
-      # search deeper
-      if next_node.is_a? CyborgHood::CyborgServerInterfaceBase
-        next_node.find_node_action(session, other_nodes_names)
-      else
-        # it is not a node, so there are no children
-        return
-      end
-    end
-
-    def child_node(next_node_name, session, *args)
-      args.unshift session if self.is_a? CyborgHood::CyborgServerStatefulInterface
-      self.send(next_node_name, *args)
-    end
-
-    def has_node?(cmd)
-      not find_node_action(nil, cmd).nil?
-    end
-
-    # preliminary incoming message handling
-    def call(session, cmd, data = nil)
-      action = find_node_action(session, cmd)
-      raise CyberError.new(:unrecoverable, 'api/cyborghood', "unknown node") if action.nil?
-
-      data ||= []
-      raise CyberError.new(:unrecoverable, 'api/cyborghood', "wrong format for arguments") unless data.is_a? Array
+      def find_child_node(child_node)
+        return @nodes[child_node] if @nodes.has_key? child_node
+
+        @nodes.each_pair do |match, node|
+          found =  if match.is_a? String
+                     child_node == match
+                   elsif match.is_a? Regexp
+                     child_node =~ Regexp.new(match)
+                   elsif match.is_a? Proc
+                     match.call.include? child_node
+                   end
+          return node if found
+        end
 
-      begin
-        action.call(*data)
-      rescue
-        logger.debug "node action error message: " + $!
-        logger.debug "node action error backtrace: " + $!.backtrace.join("\n")
-        raise CyberError.new(:unrecoverable, 'api/cyborghood', "method call failed: " + $!)
+        nil
       end
-    end
-  end
 
-  # structural mixins
-
-  module CyborgServerInterface
-    def self.included(base)
-      base.class_eval("include CyborgServerInterfaceBase")
-      base.class_eval("include Singleton")
-      base.extend(ClassMethods)
-    end
+      class Request
+        attr_reader :session, :args, :reply
 
-    module ClassMethods
-      def dynamic_interface(&resource_generator)
-        class_eval do
-          class_inheritable_reader :resource_generator
+        def initialize(session, args)
+          @session = session
+          @args = args
 
-          def method_missing(method_name, *args)
-            node_name = method_name.to_s
-            if api_methods.include?(node_name)
-              self.resource_generator.call(node_name)
-            else
-              super
-            end
-          end
+          @reply = {
+            :results   => {},
+            :infos     => [],
+            :warnings  => [],
+            :errors    => []
+          }.to_ostruct
         end
-
-        write_inheritable_attribute(:resource_generator, resource_generator)
       end
-    end
-  end
-
-  module CyborgServerEmbeddedInterface
-    def self.included(base)
-      base.class_eval("include CyborgServerInterfaceBase")
-      base.export_parent_methods
-    end
-  end
-
-  module CyborgServerStatefulInterface
-    def self.included(base)
-      base.class_eval("include CyborgServerInterfaceBase")
-      base.class_eval("include Singleton")
-      base.extend(ClassMethods)
-    end
-
-    module ClassMethods
-      def stateful_dynamic_interface(resource_key_pattern, &resource_generator)
-        class_eval do
-          class_inheritable_reader :resource_key_pattern, :resource_generator
-
-          def method_missing(method_name, *args)
-            session = args.shift
 
-            node_name = method_name.to_s
-            if api_methods.include?(node_name)
-              resource_key = self.resource_key_pattern.gsub("#NODE#", node_name)
-              session.store.get(resource_key) { self.resource_generator.call(node_name) }
-            else
-              super
-            end
+      def request(session, args)
+        if @request_cb
+          request = Request.new(session, args)
+          begin
+            @request_cb.call(request)
+            # TODO: full reply needed
+            request.reply.results
+          rescue
+            logger.debug "node request error message: " + $!
+            logger.debug "node request error backtrace: " + $!.backtrace.join("\n")
+            raise CyberError.new(:unrecoverable, 'api/cyborghood', "method call failed: " + $!)
           end
+        else
+          @nodes.keys.collect do |match|
+            if match.is_a? String
+              match
+            elsif match.is_a? Regexp
+              '/' + match.to_s + '/'
+            elsif match.is_a? Proc
+              match.call
+            end
+          end.compact.flatten
         end
-
-        write_inheritable_attribute(:resource_key_pattern, resource_key_pattern)
-        write_inheritable_attribute(:resource_generator, resource_generator)
       end
-    end
-  end
-
-  # additional mixin
-
-  module CyborgServerRootInterfaceAddon
-    API_VERSION = "0.1~"
 
-    def self.included(base)
-      list = self.public_instance_methods(false)
-      base.class_eval do
-        export_method *list
+      def cleanup
+        @nodes = {}
+        @request_cb = nil
       end
     end
-
-    def product_name
-      PRODUCT
-    end
-
-    def product_version
-      VERSION
-    end
-
-    def api_version
-      API_VERSION
-    end
-
-    def bot_name
-      @bot.name
-    end
   end
 end
diff --git a/lib/cyborghood/cyborg/botnet/protocol.rb b/lib/cyborghood/cyborg/botnet/protocol.rb
index 7f6cc39..b2bc8a4 100644
--- a/lib/cyborghood/cyborg/botnet/protocol.rb
+++ b/lib/cyborghood/cyborg/botnet/protocol.rb
@@ -99,7 +99,7 @@ module CyborgHood
       if message.action_parameters.nil?
         return send_error_action(message, "missing parameters")
       end
-      unless @conversation.bot.interface.is_node? message.action_parameters[:node]
+      unless @conversation.bot.interface._is_node?(message.conv_thread.session, message.action_parameters[:node])
         return send_error_action(message, "bad node")
       end
       send_reply_ack(message)
@@ -108,7 +108,7 @@ module CyborgHood
           :reply_message => message
         }
         begin
-          result[:action_result] = @conversation.bot.interface.call(message.conv_thread.session,
+          result[:action_result] = @conversation.bot.interface._call(message.conv_thread.session,
                                                                     message.action_parameters[:node],
                                                                     message.action_parameters[:parameters])
         rescue CyberError => e
@@ -132,7 +132,7 @@ module CyborgHood
       if message.action_parameters.nil?
         return send_error_action(message, "missing parameters")
       end
-      unless @conversation.bot.interface.is_node? message.action_parameters[:node]
+      unless @conversation.bot.interface._is_node?(message.conv_thread.session, message.action_parameters[:node])
         return send_error_action(message, "bad node")
       end
       send_reply_ack(message)
diff --git a/lib/cyborghood/cyborg/dsl.rb b/lib/cyborghood/cyborg/dsl.rb
index 82b935a..d8c1856 100644
--- a/lib/cyborghood/cyborg/dsl.rb
+++ b/lib/cyborghood/cyborg/dsl.rb
@@ -24,12 +24,21 @@ module CyborgHood
   module DSL
     class BaseDSL < ActiveSupport::BasicObject
       def initialize(&block)
-        self.instance_eval(&block)
+        _load_block(&block)
         _start_dsl
       end
 
       reveal :class
       reveal :logger
+
+      protected
+
+      def _load_block(&block)
+        self.instance_eval(&block)
+      end
+
+      def _start_dsl
+      end
     end
 
     class Task < BaseDSL
diff --git a/lib/cyborghood/services/dns.rb b/lib/cyborghood/services/dns.rb
index b305df3..03ec25e 100644
--- a/lib/cyborghood/services/dns.rb
+++ b/lib/cyborghood/services/dns.rb
@@ -50,6 +50,10 @@ module CyborgHood
           end
         end
 
+        def zones
+          master_zones + slave_zones
+        end
+
         def type
           @config.dns.software
         end
@@ -76,8 +80,8 @@ module CyborgHood
       end
 
       class Zone
-        def initialize(zone)
-          @zone = zone
+        def initialize(name)
+          @name = name
 
           @config = Config.instance
           @resolver = Dnsruby::Resolver.new
@@ -197,7 +201,7 @@ module CyborgHood
               raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: unknown nameserver")
             end
           end
-          system "sudo #{script} '#{@zone}' >/dev/null"
+          system "sudo #{script} '#{@name}' >/dev/null"
           raise CyberError.new(:unrecoverable, "services/dns", "zone activation failed") unless $?.success?
         end
 
@@ -215,7 +219,7 @@ module CyborgHood
           return unless @temp_file.nil?
 
           begin
-            @temp_file = Tempfile.new(@zone)
+            @temp_file = Tempfile.new(@name)
             @temp_file.write(@content)
             @temp_file.close
           rescue
@@ -252,7 +256,7 @@ module CyborgHood
             @content = File.read(filename)
             update_hash if filename == @filename
           rescue
-            raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' cannot be read from '#{filename}' (I/O error, nonexistent or lack of permission)")
+            raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@name}' cannot be read from '#{filename}' (I/O error, nonexistent or lack of permission)")
           end
         end
 
@@ -262,7 +266,7 @@ module CyborgHood
               fp.print @content
             end
           rescue
-            raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' cannot be written to '#{filename}' (I/O error or lack of permission)")
+            raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@name}' cannot be written to '#{filename}' (I/O error or lack of permission)")
           end
         end
 
@@ -274,11 +278,11 @@ module CyborgHood
           when 'bind'
             output = []
             begin
-              IO.popen("named-checkzone -i #{check_type} '#{@zone}' #{filename}") do |fp|
+              IO.popen("named-checkzone -i #{check_type} '#{@name}' #{filename}") do |fp|
                 output << fp.gets.chomp! until fp.eof?
               end
             rescue
-              raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' could not be checked (I/O error)")
+              raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@name}' could not be checked (I/O error)")
             end
 
             serial = nil
