summaryrefslogtreecommitdiff
path: root/lib/oxidized/model/model.rb
blob: 8bded03811bd259acddb33c009957166d0878061 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
require 'strscan'
require_relative 'outputs'

module Oxidized
  class Model
    include Oxidized::Config::Vars

    class << self
      def inherited klass
        klass.instance_variable_set '@cmd',   Hash.new { |h, k| h[k] = [] }
        klass.instance_variable_set '@cfg',   Hash.new { |h, k| h[k] = [] }
        klass.instance_variable_set '@procs', Hash.new { |h, k| h[k] = [] }
        klass.instance_variable_set '@expect', []
        klass.instance_variable_set '@comment', nil
        klass.instance_variable_set '@prompt', nil
      end

      def comment _comment = '# '
        return @comment if @comment

        @comment = block_given? ? yield : _comment
      end

      def prompt _prompt = nil
        @prompt or @prompt = _prompt
      end

      def cfg *methods, **args, &block
        [methods].flatten.each do |method|
          process_args_block(@cfg[method.to_s], args, block)
        end
      end

      def cfgs
        @cfg
      end

      def cmd _cmd = nil, **args, &block
        if _cmd.class == Symbol
          process_args_block(@cmd[_cmd], args, block)
        else
          process_args_block(@cmd[:cmd], args, [_cmd, block])
        end
        Oxidized.logger.debug "lib/oxidized/model/model.rb Added #{_cmd} to the commands list"
      end

      def cmds
        @cmd
      end

      def expect re, **args, &block
        process_args_block(@expect, args, [re, block])
      end

      def expects
        @expect
      end

      # calls the block at the end of the model, prepending the output of the
      # block to the output string
      #
      # @author Saku Ytti <saku@ytti.fi>
      # @since 0.0.39
      # @yield expects block which should return [String]
      # @return [void]
      def pre **args, &block
        process_args_block(@procs[:pre], args, block)
      end

      # calls the block at the end of the model, adding the output of the block
      # to the output string
      #
      # @author Saku Ytti <saku@ytti.fi>
      # @since 0.0.39
      # @yield expects block which should return [String]
      # @return [void]
      def post **args, &block
        process_args_block(@procs[:post], args, block)
      end

      # @author Saku Ytti <saku@ytti.fi>
      # @since 0.0.39
      # @return [Hash] hash proc procs :pre+:post to be prepended/postfixed to output
      def procs
        @procs
      end

      private

      def process_args_block(target, args, block)
        if args[:clear]
          target.replace([block])
        else
          method = args[:prepend] ? :unshift : :push
          target.send(method, block)
        end
      end
    end

    attr_accessor :input, :node

    def cmd string, &block
      Oxidized.logger.debug "lib/oxidized/model/model.rb Executing #{string}"
      out = @input.cmd(string)
      return false unless out

      out = out.b unless Oxidized.config.input.utf8_encoded?
      self.class.cmds[:all].each do |all_block|
        out = instance_exec Oxidized::String.new(out), string, &all_block
      end
      if vars :remove_secret
        self.class.cmds[:secret].each do |all_block|
          out = instance_exec Oxidized::String.new(out), string, &all_block
        end
      end
      out = instance_exec Oxidized::String.new(out), &block if block
      process_cmd_output out, string
    end

    def output
      @input.output
    end

    def send data
      @input.send data
    end

    def expect re, &block
      self.class.expect re, &block
    end

    def cfg
      self.class.cfgs
    end

    def prompt
      self.class.prompt
    end

    def expects data
      self.class.expects.each do |re, cb|
        if data.match re
          if cb.arity == 2
            data = instance_exec [data, re], &cb
          else
            data = instance_exec data, &cb
          end
        end
      end
      data
    end

    def get
      Oxidized.logger.debug 'lib/oxidized/model/model.rb Collecting commands\' outputs'
      outputs = Outputs.new
      procs = self.class.procs
      self.class.cmds[:cmd].each do |command, block|
        out = cmd command, &block
        return false unless out

        outputs << out
      end
      procs[:pre].each do |pre_proc|
        outputs.unshift process_cmd_output(instance_eval(&pre_proc), '')
      end
      procs[:post].each do |post_proc|
        outputs << process_cmd_output(instance_eval(&post_proc), '')
      end
      outputs
    end

    def comment _comment
      data = ''
      _comment.each_line do |line|
        data << self.class.comment << line
      end
      data
    end

    def screenscrape
      @input.class.to_s.match(/Telnet/) || vars(:ssh_no_exec)
    end

    private

    def process_cmd_output output, name
      output = Oxidized::String.new output if ::String === output
      output = Oxidized::String.new '' unless Oxidized::String === output
      output.set_cmd(name)
      output
    end
  end
end