#!/usr/bin/env ruby
require 'rubygems'
require 'time'
require 'omf_common'
require 'optparse'

@config = YAML.load_file('~/.omf/etc/omf_script_conf.yaml')
# @config = YAML.load_file(File.join(File.dirname(File.expand_path(__FILE__)), '.../etc/omf_script_conf.yaml'))
@auth = @config[:auth]
@xmpp = @config[:xmpp]
@omf = @config[:omf_script]

options = {}
opt_parser = OptionParser.new do |opts|
  opts.banner = "Usage: omf6 [COMMAND] [OPTIONS]"
  opts.separator ""
  opts.separator "Commands"
  opts.separator  "     load : load an image to a group of nodes"
  opts.separator  "     save : reate an image from a node"
  opts.separator  "     tell : change the status of a group of nodes (status can be on/off/reset)"
  opts.separator  "     stat : report the status of a group of nodes"
  opts.separator "Options"

  opts.on('-i', '--image IMAGE_NAME', 'the image name for load command (if nill default image will be loaded)') { |v| options[:image] = v }
  opts.on('-n', '--node NODE', 'node name for save command') { |v| options[:node] = v }
  opts.on('-a', '--status STATUS', 'the status you want to get the node to. Required only on tell command.') { |v| options[:status] = v }
  opts.on('-t', '--target_nodes NODES', 'target nodes you want to run the command too. Required on commands load, tell and stat.') {|v| options[:target_nodes] = v.split(",") }

  options[:last_action] = @omf[:last_action] #actions are reset and shutdown
  opts.on('-l', '--last_action ACTION', "action you want to perform after the commands is executed. Optional on commands load and save (last_action can be reset/shutdown. Default #{options[:last_action]})."){|v| options[:last_action] = v}
  options[:wait] = false
  opts.on('-w', '--wait', 'wait until pingable. Used in tell command (default vallue is off)'){|v| options[:wait] = true}
end

entity_cert = File.expand_path(@auth[:entity_cert])
entity_key = File.expand_path(@auth[:entity_key])
entity = OmfCommon::Auth::Certificate.create_from_pem(File.read(entity_cert))#, File.read(entity_key))

trusted_roots = File.expand_path(@auth[:root_cert_dir])

#run frisbee server
def create_frisbeed(comm, fcontroller, port, options)
  fcontroller.create(:frisbeed, hrn: 'frisbee server', image: options[:image], port: port) do |reply_msg|
    #image "/var/lib/omf-images-5.4/baseline.ndz"
    if reply_msg.success?
      server = reply_msg.resource
      @@server = server
      server.on_subscribed do
        server.on_message do |m|
          if m.operation == :inform
            if m.read_content("event") == "STDOUT"
              puts m.read_content("msg")
            elsif m.read_content("event") == "EXIT"
              puts m.read_content("msg")
            end
          end
        end
      end
    else
      error ">>> Frisbeed resource creation failed - #{reply_msg[:reason]}"
    end
  end
end

#run frisbee client on a node
def create_frisbee(comm, fcontroller, node, port, options)
  fcontroller.create(:frisbee, hrn: 'frisbee client', port: port, node_topic: "#{node.to_s}") do |reply_msg|
    if reply_msg.success?
      client = reply_msg.resource
      client.on_subscribed do
        client.on_message do |client_msg|
          if client_msg.operation == :inform
            if client_msg.read_property("event") == "STARTED"#only happens when frisbee runs with :application rc
#               @nof_nodes_up_frisbee += 1
#               if @nof_nodes == @nof_nodes_up_frisbee
#                 create_frisbeed(fcontroller, port) #frisbee server
#                 puts "load operation started."
#               end
            elsif client_msg.read_property("event") == "STDOUT"
              puts "#{client_msg.read_property("node")}: #{client_msg.read_property("msg")}"
            elsif client_msg.read_property("event") == "EXIT"
              puts "#{client_msg.read_property("node")}: #{client_msg.read_property("msg")}"
              comm.subscribe('cm_factory') do |controller|
                controller.on_message do |cm_msg|
                  if cm_msg.operation == :inform
                    case cm_msg.read_content("itype")
                    when 'STATUS'
                      unless cm_msg.read_property("current").nil? || cm_msg.read_property("desired").nil?
                        if cm_msg.read_property("current").to_sym == :pxe_off && cm_msg.read_property("desired").to_sym == :pxe_off
                          n = cm_msg.read_property("node")
                          @nodes_up_without_pxe << n
                          if @nodes_up_pxe.length == (@nodes_up_without_pxe.length + @nodes_failed_without_pxe.length)
                            puts "load proccess completed."
                            fcontroller.release(@@server) do |reply_msg|
                              comm.disconnect
                            end
                          end
                        end
                      end
                    when 'ERROR'
                      case cm_msg.read_property("event_type")
                      when "AUTH"
                        logger.info "#{cm_msg.read_property("msg")}, exit code: #{cm_msg.read_property("exit_code")}"
                        n = cm_msg.read_property("node_name")
                        @nodes_failed_without_pxe << n
                        if (@nodes_up_without_pxe.length + @nodes_failed_without_pxe.length) == options[:target_nodes].length
                          puts "load proccess completed."
                          fcontroller.release(@@server) do |reply_msg|
                            comm.disconnect
                          end
                        end
                      when "HTTP"
                        logger.info "#{cm_msg.read_property("msg")}, exit code: #{cm_msg.read_property("exit_code")}"
                        n = cm_msg.read_property("node_name")
                        if @nodes_retrying_without_pxe.include?(n)
                          @nodes_retrying_without_pxe.delete(n)
                          @nodes_failed_without_pxe << n
                          if (@nodes_up_without_pxe.length + @nodes_failed_without_pxe.length) == options[:target_nodes].length
                            fcontroller.release(@@server) do |reply_msg|
                              comm.disconnect
                            end
                          end
                        else
                          @nodes_retrying_without_pxe << n
                          controller.configure(state: {node: n.to_sym, status: :start_on_pxe})
                        end
                      when "TIME_OUT"
                        logger.info "#{cm_msg.read_property("msg")}, exit code: #{cm_msg.read_property("exit_code")}"
                        n = cm_msg.read_property("node_name")
                        @nodes_failed_without_pxe << n
                        if (@nodes_up_without_pxe.length + @nodes_failed_without_pxe.length) == options[:target_nodes].length
                          fcontroller.release(@@server) do |reply_msg|
                            comm.disconnect
                          end
                        end
                      else
                        error cm_msg.read_content('reason') if cm_msg.read_content("reason")
                      end
                    when 'WARN'
                      warn cm_msg.read_content('reason') if cm_msg.read_content("reason")
                    end
                  end
                end
                puts "#{options[:last_action]} node '#{client_msg.read_property("node")}' out of PXE."
                controller.configure(state: {node: node.to_sym, status: :start_without_pxe, last_action: options[:last_action]})
              end
            end
          end
        end
      end
    else
      error ">>> Frisbee resource creation failed - #{reply_msg[:reason]}"
    end
  end
end

def load(comm, options)
  comm.subscribe('cm_factory') do |controller|
    #TODO handle the case some nodes are not up and running
    unless controller.error?
      @nof_nodes = options[:target_nodes].length
      @nodes_up_without_pxe = []
      @nodes_failed_without_pxe = []
      @nodes_retrying_without_pxe = []
      @nodes_up_pxe = []
      nodes_failed_pxe = []
      nodes_retrying_pxe = []
      port = nil
      controller.on_message do |m|
        if m.operation == :inform
          case m.read_content("itype")
          when 'STATUS'
            unless m.read_property("current").nil? && m.read_property("desired").nil?
              if m.read_property("current").to_sym == :pxe_on && m.read_property("desired").to_sym == :pxe_on
                n = m.read_property("node_name")
                @nodes_up_pxe << n
                if @nof_nodes == (@nodes_up_pxe.length + nodes_failed_pxe.length) #all nodes are up and running on pxe
                  puts "all nodes are up and running on pxe."
                  comm.subscribe('frisbee_factory') do |fcontroller|
                    puts "requesting available port"
                    fcontroller.request([:ports]) do |m|
                      port = m.read_property("ports")
                      puts "running frisbee server on port '#{port}'"
                      create_frisbeed(comm, fcontroller, port, options)
                      @nodes_up_pxe.each do |node|
                        create_frisbee(comm, fcontroller, node, port, options) #frisbee client
                      end
                      puts "running frisbee client on specified nodes."
                    end
                  end
                end
              else
                error "exit code: #{m.read_content('exit_code')}" if m.read_content('exit_code')
              end
            end
          when 'ERROR'
            case m.read_property("event_type")
            when "AUTH"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              nodes_failed_pxe << n
              if @nof_nodes == (@nodes_up_pxe.length + nodes_failed_pxe.length) #all nodes are up and running on pxe
                puts "all nodes are up and running on pxe."
                comm.subscribe('frisbee_factory') do |fcontroller|
                  puts "requesting available port"
                  fcontroller.request([:ports]) do |m|
                    port = m.read_property("ports")
                    puts "running frisbee server on port '#{port}'"
                    create_frisbeed(comm, fcontroller, port, options)
                    @nodes_up_pxe.each do |node|
                      create_frisbee(comm, fcontroller, node, port, options) #frisbee client
                    end
                    puts "running frisbee client on specified nodes."
                  end
                end
              end
            when "HTTP"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              if nodes_retrying_pxe.include?(n)
                nodes_retrying_pxe.delete(n)
                nodes_failed_pxe << n
                if @nof_nodes == (@nodes_up_pxe.length + nodes_failed_pxe.length) #all nodes are up and running on pxe
                  puts "all nodes are up and running on pxe."
                  comm.subscribe('frisbee_factory') do |fcontroller|
                    puts "requesting available port"
                    fcontroller.request([:ports]) do |m|
                      port = m.read_property("ports")
                      puts "running frisbee server on port '#{port}'"
                      create_frisbeed(comm, fcontroller, port, options)
                      @nodes_up_pxe.each do |node|
                        create_frisbee(comm, fcontroller, node, port, options) #frisbee client
                      end
                      puts "running frisbee client on specified nodes."
                    end
                  end
                end
              else
                nodes_retrying_pxe << n
                controller.configure(state: {node: n.to_sym, status: :start_on_pxe})
              end
            when "TIME_OUT"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              nodes_failed_pxe << n
              if @nof_nodes == (@nodes_up_pxe.length + nodes_failed_pxe.length) #all nodes are up and running on pxe
                puts "all nodes are up and running on pxe."
                comm.subscribe('frisbee_factory') do |fcontroller|
                  puts "requesting available port"
                  fcontroller.request([:ports]) do |m|
                    port = m.read_property("ports")
                    puts "running frisbee server on port '#{port}'"
                    create_frisbeed(comm, fcontroller, port, options)
                    @nodes_up_pxe.each do |node|
                      create_frisbee(comm, fcontroller, node, port, options) #frisbee client
                    end
                    puts "running frisbee client on specified nodes."
                  end
                end
              end
            else
              error m.read_content('reason') if m.read_content("reason")
            end
          when 'WARN'
            warn cm_msg.read_content('reason') if m.read_content("reason")
          end
        end
      end
      options[:target_nodes].each do |node|
        controller.configure(state: {node: node.to_sym, status: :start_on_pxe})
      end
      puts "waiting for target nodes to boot on PXE."
    else
      error controller.inspect
    end
  end
end

#run imagezip server
def create_imagezip_server(comm, fcontroller, port, options)
  fcontroller.create(:imagezip_server, {hrn: 'imagezip server', image: options[:image], port: port}) do |reply_msg|
    if reply_msg.success?
      server = reply_msg.resource
      @@server = server
      server.on_subscribed do
        server.on_message do |m|
          if m.operation == :inform
            if m.read_content("event") == "STDOUT"
              puts m.read_content("msg")
            elsif m.read_content("event") == "EXIT"
              puts m.read_content("msg")
            end
          end
        end
      end
    else
      error ">>> Imagezip Server resource creation failed - #{reply_msg[:reason]}"
    end
  end
end

#run imagezip client on a node
def create_imagezip_client(comm, fcontroller, node, port, options)
  fcontroller.create(:imagezip_client, {hrn: 'imagezip client', port: port, node_topic: "#{node.to_s}"}) do |reply_msg|
    if reply_msg.success?
      client = reply_msg.resource
      client.on_subscribed do
        client.on_message do |client_msg|
          if client_msg.operation == :inform
            if client_msg.read_property("event") == "STDOUT"
              print "#{client_msg.read_property("msg")}"
            elsif client_msg.read_property("event") == "EXIT"
              puts "#{client_msg.read_property("node")}: #{client_msg.read_property("msg")}"
              comm.subscribe('cm_factory') do |controller|
                controller.on_message do |cm_msg|
                  if cm_msg.operation == :inform
                    case cm_msg.read_content("itype")
                    when 'STATUS'
                      unless cm_msg.read_property("current").nil? && cm_msg.read_property("desired").nil?
                        if cm_msg.read_property("current").to_sym == :pxe_off && cm_msg.read_property("desired").to_sym == :pxe_off
                          puts "save proccess completed. Image was saved in directory '/var/lib/omf-images-6'"
                          fcontroller.release(@@server) do |reply_msg|
                            comm.disconnect
                          end
                        end
                      end
                    when 'ERROR'
                      case cm_msg.read_property("event_type")
                      when "AUTH"
                        logger.info "#{cm_msg.read_property("msg")}, exit code: #{cm_msg.read_property("exit_code")}"
                        fcontroller.release(@@server) do |reply_msg|
                          comm.disconnect
                        end
                      when "HTTP"
                        logger.info "#{cm_msg.read_property("msg")}, exit code: #{cm_msg.read_property("exit_code")}"
                        if @retried
                          fcontroller.release(@@server) do |reply_msg|
                            comm.disconnect
                          end
                        else
                          @retried = true
                          controller.configure(state: {node: node.to_sym, status: :start_without_pxe, last_action: options[:last_action]})
                        end
                      when "TIME_OUT"
                        logger.info "#{cm_msg.read_property("msg")}, exit code: #{cm_msg.read_property("exit_code")}"
                        fcontroller.release(@@server) do |reply_msg|
                          comm.disconnect
                        end
                      else
                        error cm_msg.read_content('reason') if cm_msg.read_content("reason")
                      end
                    when 'WARN'
                      warn cm_msg.read_content('reason') if cm_msg.read_content("reason")
                    end
                  end
                end
                puts "#{options[:last_action]} node '#{client_msg.read_property("node")}' out of PXE."
                controller.configure(state: {node: node.to_sym, status: :start_without_pxe, last_action: options[:last_action]})
              end
            end
          end
        end
      end
    else
      error ">>> Frisbee resource creation failed - #{reply_msg[:reason]}"
    end
  end
end

def save(comm, options)
  comm.subscribe('cm_factory') do |controller|
    @retried = false
    unless controller.error?
      port = nil
      controller.on_message do |m|
        if m.operation == :inform
          puts m.inspect
          case m.read_content("itype")
          when 'STATUS'
            unless m.read_property("current").nil? && m.read_property("desired").nil?
              logger.info "#{m.read_property("node_name")}, current: #{m.read_property("current")}, desired: #{m.read_property("desired")}"
              if m.read_property("current").to_sym == :pxe_on && m.read_property("desired").to_sym == :pxe_on
                puts "node is up and running on pxe."
                comm.subscribe('frisbee_factory') do |fcontroller|
                  puts "requesting available port"
                  fcontroller.request([:ports]) do |m|
                    port = m.read_property("ports")
                    puts "running imagezip server on port #{port}."
                    create_imagezip_server(comm, fcontroller, port, options)
                    sleep 2
                    puts "running imagezip client on node."
                    create_imagezip_client(comm, fcontroller, options[:node], port, options)
                  end
                end
              else
                error "exit code: #{m.read_content('exit_code')}" if m.read_content('exit_code')
              end
            end
          when 'ERROR'
            case m.read_property("event_type")
            when "AUTH"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              comm.disconnect
            when "HTTP"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              if @retried
                comm.disconnect
              else
                @retried = true
                controller.configure(state: {node: options[:node].to_sym, status: :start_on_pxe})
              end
            when "TIME_OUT"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              comm.disconnect
            else
              error m.read_content('reason') if m.read_content("reason")
            end
          when 'WARN'
            warn m.read_content('reason') if m.read_content("reason")
          end
        end
      end

      controller.configure(state: {node: options[:node].to_sym, status: :start_on_pxe})
      puts "waiting for node to boot on PXE."
    else
      error controller.inspect
    end
  end
end

def tell(comm, options)
  comm.subscribe('cm_factory') do |controller|
    unless controller.error?
      nodes_failed = []
      nodes_ok = []
      nodes_retrying = []
      controller.on_message do |m|
        if m.operation == :inform
          case m.read_content("itype")
          when 'STATUS'
            unless m.read_property("current").nil? && m.read_property("desired").nil?
              if m.read_property("current") != m.read_property("desired")
                if options[:wait]
                  puts "Waiting for node '#{m.read_property("node_name")}'."
                  logger.info "#{m.read_property("node_name")} is #{m.read_property("current")}."
                else
                  n = m.read_property("node_name")
                  nodes_ok << n
                  if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                    puts "all nodes are running." #TODO messages for failed nodes
                    comm.disconnect
                  end
                end
              else
                n = m.read_property("node_name")
                nodes_ok << n
                if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                  puts "all nodes are #{m.read_property("desired")}." #TODO messages for failed nodes
                  comm.disconnect
                end
              end
            end
          when 'ERROR'
            case m.read_property("event_type")
            when "AUTH"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              nodes_failed << n
              if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                comm.disconnect
              end
            when "HTTP"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              if nodes_retrying.include?(n)
                nodes_retrying.delete(n)
                nodes_failed << n
                if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                  comm.disconnect
                end
              else
                nodes_retrying << n
                info "retrying to send message #{options[:status]} to node #{n}"
                controller.configure(state: {node: n.to_sym, status: options[:status].to_sym})
              end
            when "TIME_OUT"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              nodes_failed << n
              if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                comm.disconnect
              end
            else
              error m.read_content('reason') if m.read_content("reason")
              comm.disconnect
            end
          when 'WARN'
            warn m.read_content('reason') if m.read_content("reason")
          end
        end
      end
      if options[:status] == "on"
        options[:target_nodes].each do |node|
          controller.configure(state: {node: node.to_sym, status: :on, wait: options[:wait]})
        end
      elsif options[:status] == "off"
        options[:target_nodes].each do |node|
          controller.configure(state: {node: node.to_sym, status: :off, wait: options[:wait]})
        end
      elsif options[:status] == "reset"
        options[:target_nodes].each do |node|
          controller.configure(state: {node: node.to_sym, status: :reset, wait: options[:wait]})
        end
      else
        puts "Invalid value for -a, only on/off/reset values are available."
        puts opt_parser
        comm.disconnect
      end
      unless options[:wait]
        puts "Proccess complete."
        comm.disconnect
      end
    else
      error controller.inspect
    end
  end
end

def stat(comm, options)
  comm.subscribe('cm_factory') do |controller|
    unless controller.error?
      nodes_failed = []
      nodes_ok = []
      nodes_retrying = []
      controller.on_message do |m|
        if m.operation == :inform
          case m.read_content("itype")
          when 'STATUS'
            unless m.read_property("current").nil?
              puts "#{m.read_property("node_name")} is #{m.read_property("current")}"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              nodes_ok << n
              if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                comm.disconnect
              end
#             elsif m.read_property("event_type") == "EXIT"
#               puts "ERROR: #{m.read_property("node")} - #{m.read_property("msg")}"
#               logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
#               nof_nodes += 1
#               if nof_nodes == options[:target_nodes].length
#                 comm.disconnect
#               end
            end
          when 'ERROR'
            case m.read_property("event_type")
            when "AUTH"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              nodes_failed << n
              if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                comm.disconnect
              end
            when "HTTP"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              if nodes_retrying.include?(n)
                nodes_retrying.delete(n)
                nodes_failed << n
                if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                  comm.disconnect
                end
              else
                nodes_retrying << n
                info "retrying to send message #{options[:status]} to node #{n}"
                controller.configure(state: {node: n.to_sym, status: :get_status})
              end
            when "TIME_OUT"
              logger.info "#{m.read_property("msg")}, exit code: #{m.read_property("exit_code")}"
              n = m.read_property("node_name")
              nodes_failed << n
              if (nodes_ok.length + nodes_failed.length) == options[:target_nodes].length
                comm.disconnect
              end
            else
              error m.read_content('reason') if m.read_content("itype") == 'ERROR'
              comm.disconnect
            end
          when 'WARN'
            warn m.read_content('reason') if m.read_content("itype") == 'WARN'
          end
        end
      end

      options[:target_nodes].each do |node|
        controller.configure(state: {node: node.to_sym, status: :get_status})
      end
    else
      error controller.inspect
      comm.disconnect
    end
  end
end

opt_parser.parse!

OmfCommon.init(@config[:operationMode], communication: { url: "xmpp://#{@xmpp[:script_user]}:#{@xmpp[:password]}@#{@xmpp[:server]}", auth: {} }) do
  OmfCommon.comm.on_connected do |comm|
    OmfCommon::Auth::CertificateStore.instance.register_default_certs(trusted_roots)
    entity.resource_id = OmfCommon.comm.local_topic.address
    OmfCommon::Auth::CertificateStore.instance.register(entity)

    info "Test script >> Connected to XMPP"

    case ARGV[0]
    when "load"
      if options[:node].nil? && options[:status].nil? && !options[:target_nodes].nil?
        if options[:last_action] == "reset" || options[:last_action] == "shutdown"
          puts "call load on options #{options.inspect}"
          load(comm, options)
        else
          puts "Invalid value for -l, only reset/shutdown values are available."
          puts opt_parser
          comm.disconnect
        end
      else
        puts "Invalid arguements."
        puts opt_parser
        comm.disconnect
      end
    when "save"
      if options[:image].nil? && !options[:node].nil? && options[:status].nil? && options[:target_nodes].nil?
        if options[:last_action] == "reset" || options[:last_action] == "shutdown"
          puts "call save on options #{options.inspect}"
          save(comm, options)
        else
          puts "Invalid value for -l, only reset/shutdown values are available."
          puts opt_parser
          comm.disconnect
        end
      else
        puts "Invalid arguements."
        puts opt_parser
        comm.disconnect
      end
    when "tell"
      if options[:image].nil? && options[:node].nil? && !options[:status].nil? && !options[:target_nodes].nil?
        if options[:status] == "on" || options[:status] == "off" || options[:status] == "reset"
          puts "call tell on options #{options.inspect}"
          tell(comm, options)
        else
          puts "Invalid value for -a, only on/off/reset values are available."
          puts opt_parser
          comm.disconnect
        end
      else
        puts "Invalid arguements."
        puts opt_parser
        comm.disconnect
      end
    when "stat"
      if options[:image].nil? && options[:node].nil? && options[:status].nil? && !options[:target_nodes].nil?
        puts "call stat on options #{options.inspect}"
        stat(comm, options)
      else
        puts "Invalid arguements."
        puts opt_parser
        comm.disconnect
      end
    else
      puts "Invalid command / options."
      puts opt_parser
      comm.disconnect
    end

    comm.on_interrupted { comm.disconnect }
  end
end