diff options
Diffstat (limited to 'lib')
127 files changed, 1790 insertions, 1579 deletions
diff --git a/lib/oxidized/cli.rb b/lib/oxidized/cli.rb index 9a09d41..23cc28c 100644 --- a/lib/oxidized/cli.rb +++ b/lib/oxidized/cli.rb @@ -40,11 +40,11 @@ module Oxidized end def parse_opts - opts = Slop.new(:help=>true) do + opts = Slop.new(:help => true) do on 'd', 'debug', 'turn on debugging' on 'daemonize', 'Daemonize/fork the process' on 'v', 'version', 'show version' do - puts Oxidized::VERSION + puts Oxidized::VERSION_FULL Kernel.exit end end @@ -62,7 +62,7 @@ module Oxidized def write_pid if pidfile? begin - File.open(pidfile, ::File::CREAT | ::File::EXCL | ::File::WRONLY){|f| f.write("#{Process.pid}") } + File.open(pidfile, ::File::CREAT | ::File::EXCL | ::File::WRONLY) { |f| f.write("#{Process.pid}") } at_exit { File.delete(pidfile) if File.exists?(pidfile) } rescue Errno::EEXIST check_pid diff --git a/lib/oxidized/config.rb b/lib/oxidized/config.rb index 47544fb..36d9d73 100644 --- a/lib/oxidized/config.rb +++ b/lib/oxidized/config.rb @@ -13,13 +13,14 @@ module Oxidized HookDir = File.join Directory, %w(lib oxidized hook) Sleep = 1 - def self.load(cmd_opts={}) + def self.load(cmd_opts = {}) asetus = Asetus.new(name: 'oxidized', load: false, key_to_s: true) Oxidized.asetus = asetus asetus.default.username = 'username' asetus.default.password = 'password' asetus.default.model = 'junos' + asetus.default.resolve_dns = true # if false, don't resolve DNS to IP asetus.default.interval = 3600 asetus.default.use_syslog = false asetus.default.debug = false @@ -34,10 +35,11 @@ module Oxidized asetus.default.models = {} # model level configuration asetus.default.pid = File.join(Oxidized::Config::Root, 'pid') - asetus.default.input.default = 'ssh, telnet' - asetus.default.input.debug = false # or String for session log file - asetus.default.input.ssh.secure = false # complain about changed certs - asetus.default.input.ftp.passive= true # ftp passive mode + asetus.default.input.default = 'ssh, telnet' + asetus.default.input.debug = false # or String for session log file + asetus.default.input.ssh.secure = false # complain about changed certs + asetus.default.input.ftp.passive = true # ftp passive mode + asetus.default.input.utf8_encoded = true # configuration is utf8 encoded or ascii-8bit asetus.default.output.default = 'file' # file, git asetus.default.source.default = 'csv' # csv, sql diff --git a/lib/oxidized/core.rb b/lib/oxidized/core.rb index e007c9d..440d8e2 100644 --- a/lib/oxidized/core.rb +++ b/lib/oxidized/core.rb @@ -11,9 +11,9 @@ module Oxidized def initialize args Oxidized.mgr = Manager.new Oxidized.Hooks = HookManager.from_config(Oxidized.config) - nodes = Nodes.new + nodes = Nodes.new raise NoNodesFound, 'source returns no usable nodes' if nodes.size == 0 - @worker = Worker.new nodes + @worker = Worker.new nodes trap('HUP') { nodes.load } if Oxidized.config.rest? begin @@ -22,7 +22,7 @@ module Oxidized raise OxidizedError, 'oxidized-web not found: sudo gem install oxidized-web - \ or disable web support by setting "rest: false" in your configuration' end - @rest = API::Web.new nodes, Oxidized.config.rest + @rest = API::Web.new nodes, Oxidized.config.rest @rest.run end run diff --git a/lib/oxidized/hook.rb b/lib/oxidized/hook.rb index c27f6fd..915299b 100644 --- a/lib/oxidized/hook.rb +++ b/lib/oxidized/hook.rb @@ -1,89 +1,88 @@ module Oxidized -class HookManager - class << self - def from_config cfg - mgr = new - cfg.hooks.each do |name,h_cfg| - h_cfg.events.each do |event| - mgr.register event.to_sym, name, h_cfg.type, h_cfg + class HookManager + class << self + def from_config cfg + mgr = new + cfg.hooks.each do |name, h_cfg| + h_cfg.events.each do |event| + mgr.register event.to_sym, name, h_cfg.type, h_cfg + end end + mgr end - mgr end - end - - # HookContext is passed to each hook. It can contain anything related to the - # event in question. At least it contains the event name - class HookContext < OpenStruct; end - # RegisteredHook is a container for a Hook instance - class RegisteredHook < Struct.new(:name, :hook); end + # HookContext is passed to each hook. It can contain anything related to the + # event in question. At least it contains the event name + class HookContext < OpenStruct; end - Events = [ - :node_success, - :node_fail, - :post_store, - :nodes_done - ] - attr_reader :registered_hooks + # RegisteredHook is a container for a Hook instance + class RegisteredHook < Struct.new(:name, :hook); end - def initialize - @registered_hooks = Hash.new {|h,k| h[k] = []} - end + Events = [ + :node_success, + :node_fail, + :post_store, + :nodes_done + ] + attr_reader :registered_hooks - def register event, name, hook_type, cfg - unless Events.include? event - raise ArgumentError, - "unknown event #{event}, available: #{Events.join ','}" + def initialize + @registered_hooks = Hash.new { |h, k| h[k] = [] } end - Oxidized.mgr.add_hook hook_type - begin - hook = Oxidized.mgr.hook.fetch(hook_type).new - rescue KeyError - raise KeyError, "cannot find hook #{hook_type.inspect}" - end + def register event, name, hook_type, cfg + unless Events.include? event + raise ArgumentError, + "unknown event #{event}, available: #{Events.join ','}" + end - hook.cfg = cfg + Oxidized.mgr.add_hook hook_type + begin + hook = Oxidized.mgr.hook.fetch(hook_type).new + rescue KeyError + raise KeyError, "cannot find hook #{hook_type.inspect}" + end - @registered_hooks[event] << RegisteredHook.new(name, hook) - Oxidized.logger.debug "Hook #{name.inspect} registered #{hook.class} for event #{event.inspect}" - end + hook.cfg = cfg - def handle event, ctx_params={} - ctx = HookContext.new ctx_params - ctx.event = event + @registered_hooks[event] << RegisteredHook.new(name, hook) + Oxidized.logger.debug "Hook #{name.inspect} registered #{hook.class} for event #{event.inspect}" + end - @registered_hooks[event].each do |r_hook| - begin - r_hook.hook.run_hook ctx - rescue => e - Oxidized.logger.error "Hook #{r_hook.name} (#{r_hook.hook}) failed " + - "(#{e.inspect}) for event #{event.inspect}" + def handle event, ctx_params = {} + ctx = HookContext.new ctx_params + ctx.event = event + + @registered_hooks[event].each do |r_hook| + begin + r_hook.hook.run_hook ctx + rescue => e + Oxidized.logger.error "Hook #{r_hook.name} (#{r_hook.hook}) failed " + + "(#{e.inspect}) for event #{event.inspect}" + end end end end -end -# Hook abstract base class -class Hook - attr_reader :cfg + # Hook abstract base class + class Hook + attr_reader :cfg - def initialize - end + def initialize + end - def cfg=(cfg) - @cfg = cfg - validate_cfg! if self.respond_to? :validate_cfg! - end + def cfg=(cfg) + @cfg = cfg + validate_cfg! if self.respond_to? :validate_cfg! + end - def run_hook ctx - raise NotImplementedError - end + def run_hook ctx + raise NotImplementedError + end - def log(msg, level=:info) - Oxidized.logger.send(level, "#{self.class.name}: #{msg}") + def log(msg, level = :info) + Oxidized.logger.send(level, "#{self.class.name}: #{msg}") + end end - -end end diff --git a/lib/oxidized/hook/awssns.rb b/lib/oxidized/hook/awssns.rb index dbc2d47..183cd2c 100644 --- a/lib/oxidized/hook/awssns.rb +++ b/lib/oxidized/hook/awssns.rb @@ -19,9 +19,8 @@ class AwsSns < Oxidized::Hook :node => ctx.node.name.to_s ) end - topic.publish({ + topic.publish( message: message.to_json - }) + ) end - end diff --git a/lib/oxidized/hook/ciscosparkdiff.rb b/lib/oxidized/hook/ciscosparkdiff.rb new file mode 100644 index 0000000..e45d7c6 --- /dev/null +++ b/lib/oxidized/hook/ciscosparkdiff.rb @@ -0,0 +1,49 @@ +require 'cisco_spark' + +# defaults to posting a diff, if messageformat is supplied them a message will be posted too +# diffenable defaults to true +# Modified from slackdiff + +class CiscoSparkDiff < Oxidized::Hook + def validate_cfg! + raise KeyError, 'hook.accesskey is required' unless cfg.has_key?('accesskey') + raise KeyError, 'hook.space is required' unless cfg.has_key?('space') + end + + def run_hook(ctx) + return unless ctx.node + return unless ctx.event.to_s == "post_store" + log "Connecting to Cisco Spark" + CiscoSpark.configure do |config| + config.api_key = cfg.accesskey + config.proxy = cfg.proxy if cfg.has_key?('proxy') + end + space = cfg.space + client = CiscoSpark::Room.new(id: space) + client.fetch + log "Connected" + diffenable = true + if cfg.has_key?('diff') == true + if cfg.diff == false + diffenable = false + end + end + if diffenable == true + gitoutput = ctx.node.output.new + diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil + title = ctx.node.name.to_s + log "Posting diff as snippet to #{cfg.space}" + message = CiscoSpark::Message.new(text: 'Device ' + title + ' modified:' + "\n" + diff[:patch].lines.to_a[4..-1].join) + room = CiscoSpark::Room.new(id: space) + room.send_message(message) + end + if cfg.has_key?('message') == true + log cfg.message + msg = cfg.message % { :node => ctx.node.name.to_s, :group => ctx.node.group.to_s, :commitref => ctx.commitref, :model => ctx.node.model.class.name.to_s.downcase } + log msg + log "Posting message to #{cfg.space}" + client.chat_postMessage(channel: cfg.channel, text: msg, as_user: true) + end + log "Finished" + end +end diff --git a/lib/oxidized/hook/exec.rb b/lib/oxidized/hook/exec.rb index 3f984c2..069b888 100644 --- a/lib/oxidized/hook/exec.rb +++ b/lib/oxidized/hook/exec.rb @@ -23,10 +23,9 @@ class Exec < Oxidized::Hook @cmd = cfg.cmd raise "invalid cmd value" unless @cmd.is_a?(String) || @cmd.is_a?(Array) end - rescue RuntimeError => e raise ArgumentError, - "#{self.class.name}: configuration invalid: #{e.message}" + "#{self.class.name}: configuration invalid: #{e.message}" end def run_hook ctx @@ -45,7 +44,7 @@ class Exec < Oxidized::Hook def run_cmd! env pid, status = nil, nil Timeout.timeout(@timeout) do - pid = spawn env, @cmd , :unsetenv_others => true + pid = spawn env, @cmd, :unsetenv_others => true pid, status = wait2 pid unless status.exitstatus.zero? msg = "#{@cmd.inspect} failed with exit value #{status.exitstatus}" @@ -53,11 +52,11 @@ class Exec < Oxidized::Hook raise msg end end - rescue TimeoutError + rescue Timeout::Error kill "TERM", pid msg = "#{@cmd} timed out" log msg, :error - raise TimeoutError, msg + raise Timeout::Error, msg end def make_env ctx diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index f74b22a..e077d5d 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -35,26 +35,32 @@ class GithubRepo < Oxidized::Hook end Rugged::Commit.create(repo, { - parents: [repo.head.target, their_branch.target], - tree: merge_index.write_tree(repo), - message: "Merge remote-tracking branch '#{their_branch.name}'", - update_ref: "HEAD" - }) + parents: [repo.head.target, their_branch.target], + tree: merge_index.write_tree(repo), + message: "Merge remote-tracking branch '#{their_branch.name}'", + update_ref: "HEAD" + }) end private def credentials - @credentials ||= if cfg.has_key?('username') && cfg.has_key?('password') - log "Using https auth", :debug - Rugged::Credentials::UserPassword.new(username: cfg.username, password: cfg.password) - else - if cfg.has_key?('publickey') && cfg.has_key?('privatekey') - log "Using ssh auth with key", :debug - Rugged::Credentials::SshKey.new(username: 'git', publickey: File.expand_path(cfg.publickey), privatekey: File.expand_path(cfg.privatekey), passphrase: ENV["OXIDIZED_SSH_PASSPHRASE"]) + Proc.new do |url, username_from_url, allowed_types| + if cfg.has_key?('username') + git_user = cfg.username + else + git_user = username_from_url ? username_from_url : 'git' + end + + if cfg.has_key?('password') + log "Authenticating using username and password as '#{git_user}'", :debug + Rugged::Credentials::UserPassword.new(username: git_user, password: cfg.password) + elsif cfg.has_key?('publickey') && cfg.has_key?('privatekey') + log "Authenticating using ssh keys as '#{git_user}'", :debug + Rugged::Credentials::SshKey.new(username: git_user, publickey: File.expand_path(cfg.publickey), privatekey: File.expand_path(cfg.privatekey), passphrase: ENV["OXIDIZED_SSH_PASSPHRASE"]) else - log "Using ssh auth with agentforwarding", :debug - Rugged::Credentials::SshKeyFromAgent.new(username: 'git') + log "Authenticating using ssh agent as '#{git_user}'", :debug + Rugged::Credentials::SshKeyFromAgent.new(username: git_user) end end end diff --git a/lib/oxidized/hook/slackdiff.rb b/lib/oxidized/hook/slackdiff.rb index 7cd4465..baaf291 100644 --- a/lib/oxidized/hook/slackdiff.rb +++ b/lib/oxidized/hook/slackdiff.rb @@ -10,47 +10,44 @@ class SlackDiff < Oxidized::Hook end def run_hook(ctx) - if ctx.node - if ctx.event.to_s == "post_store" - log "Connecting to slack" - Slack.configure do |config| - config.token = cfg.token - config.proxy = cfg.proxy if cfg.has_key?('proxy') - end - client = Slack::Client.new - client.auth_test - log "Connected" - # diff snippet - default - diffenable = true - if cfg.has_key?('diff') == true - if cfg.diff == false - diffenable = false - end - end - if diffenable == true - gitoutput = ctx.node.output.new - diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil - unless diff == "no diffs" - title = "#{ctx.node.name.to_s} #{ctx.node.group.to_s} #{ctx.node.model.class.name.to_s.downcase}" - log "Posting diff as snippet to #{cfg.channel}" - client.files_upload(channels: cfg.channel, as_user: true, - content: diff[:patch].lines.to_a[4..-1].join, - filetype: "diff", - title: title, - filename: "change" - ) - end - end - #Â message custom formatted - optional - if cfg.has_key?('message') == true - log cfg.message - msg = cfg.message % {:node => ctx.node.name.to_s, :group => ctx.node.group.to_s, :commitref => ctx.commitref, :model => ctx.node.model.class.name.to_s.downcase} - log msg - log "Posting message to #{cfg.channel}" - client.chat_postMessage(channel: cfg.channel, text: msg, as_user: true) - end - log "Finished" + return unless ctx.node + return unless ctx.event.to_s == "post_store" + log "Connecting to slack" + Slack.configure do |config| + config.token = cfg.token + config.proxy = cfg.proxy if cfg.has_key?('proxy') + end + client = Slack::Client.new + client.auth_test + log "Connected" + # diff snippet - default + diffenable = true + if cfg.has_key?('diff') == true + if cfg.diff == false + diffenable = false + end + end + if diffenable == true + gitoutput = ctx.node.output.new + diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil + unless diff == "no diffs" + title = "#{ctx.node.name} #{ctx.node.group} #{ctx.node.model.class.name.to_s.downcase}" + log "Posting diff as snippet to #{cfg.channel}" + client.files_upload(channels: cfg.channel, as_user: true, + content: diff[:patch].lines.to_a[4..-1].join, + filetype: "diff", + title: title, + filename: "change") end end + # message custom formatted - optional + if cfg.has_key?('message') == true + log cfg.message + msg = cfg.message % { :node => ctx.node.name.to_s, :group => ctx.node.group.to_s, :commitref => ctx.commitref, :model => ctx.node.model.class.name.to_s.downcase } + log msg + log "Posting message to #{cfg.channel}" + client.chat_postMessage(channel: cfg.channel, text: msg, as_user: true) + end + log "Finished" end end diff --git a/lib/oxidized/hook/xmppdiff.rb b/lib/oxidized/hook/xmppdiff.rb index 396d1b3..6acb172 100644 --- a/lib/oxidized/hook/xmppdiff.rb +++ b/lib/oxidized/hook/xmppdiff.rb @@ -7,54 +7,52 @@ class XMPPDiff < Oxidized::Hook raise KeyError, 'hook.password is required' unless cfg.has_key?('password') raise KeyError, 'hook.channel is required' unless cfg.has_key?('channel') raise KeyError, 'hook.nick is required' unless cfg.has_key?('nick') - end + end def run_hook(ctx) - if ctx.node - if ctx.event.to_s == "post_store" - begin - Timeout::timeout(15) do - gitoutput = ctx.node.output.new - diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil - - interesting = diff[:patch].lines.to_a[4..-1].any? { |line| - ["+", "-"].include?(line[0]) and not ["#", "!"].include?(line[1]) - } - interesting &&= diff[:patch].lines.to_a[5..-1].any? { |line| line[0] == '-' } - interesting &&= diff[:patch].lines.to_a[5..-1].any? { |line| line[0] == '+' } + return unless ctx.node + return unless ctx.event.to_s == "post_store" + begin + Timeout.timeout(15) do + gitoutput = ctx.node.output.new + diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil + + interesting = diff[:patch].lines.to_a[4..-1].any? do |line| + ["+", "-"].include?(line[0]) and not ["#", "!"].include?(line[1]) + end + interesting &&= diff[:patch].lines.to_a[5..-1].any? { |line| line[0] == '-' } + interesting &&= diff[:patch].lines.to_a[5..-1].any? { |line| line[0] == '+' } - if interesting - log "Connecting to XMPP" - client = Jabber::Client.new(Jabber::JID.new(cfg.jid)) - client.connect - sleep 1 - client.auth(cfg.password) - sleep 1 + if interesting + log "Connecting to XMPP" + client = Jabber::Client.new(Jabber::JID.new(cfg.jid)) + client.connect + sleep 1 + client.auth(cfg.password) + sleep 1 - log "Connected" + log "Connected" - m = Jabber::MUC::SimpleMUCClient.new(client) - m.join(cfg.channel + "/" + cfg.nick) + m = Jabber::MUC::SimpleMUCClient.new(client) + m.join(cfg.channel + "/" + cfg.nick) - log "Joined" + log "Joined" - title = "#{ctx.node.name.to_s} #{ctx.node.group.to_s} #{ctx.node.model.class.name.to_s.downcase}" - log "Posting diff as snippet to #{cfg.channel}" + title = "#{ctx.node.name} #{ctx.node.group} #{ctx.node.model.class.name.to_s.downcase}" + log "Posting diff as snippet to #{cfg.channel}" - m.say(title + "\n\n" + diff[:patch].lines.to_a[4..-1].join) + m.say(title + "\n\n" + diff[:patch].lines.to_a[4..-1].join) - sleep 1 + sleep 1 - client.close + client.close - log "Finished" + log "Finished" - end - end - rescue Timeout::Error - log "timed out" end end + rescue Timeout::Error + log "timed out" end end end diff --git a/lib/oxidized/input/cli.rb b/lib/oxidized/input/cli.rb index 660e173..d434e33 100644 --- a/lib/oxidized/input/cli.rb +++ b/lib/oxidized/input/cli.rb @@ -32,26 +32,25 @@ module Oxidized @pre_logout.each { |command, block| block ? block.call : (cmd command, nil) } end - def post_login _post_login=nil, &block + def post_login _post_login = nil, &block unless @exec @post_login << [_post_login, block] end end - def pre_logout _pre_logout=nil, &block + def pre_logout _pre_logout = nil, &block unless @exec - @pre_logout << [_pre_logout, block] + @pre_logout << [_pre_logout, block] end end - def username re=/^(Username|login)/ + def username re = /^(Username|login)/ @username or @username = re end - def password re=/^Password/ + def password re = /^Password/ @password or @password = re end - end end end diff --git a/lib/oxidized/input/ftp.rb b/lib/oxidized/input/ftp.rb index cdf3688..ebe50ef 100644 --- a/lib/oxidized/input/ftp.rb +++ b/lib/oxidized/input/ftp.rb @@ -6,22 +6,22 @@ module Oxidized class FTP < Input RescueFail = { :debug => [ - #Net::SSH::Disconnect, + # Net::SSH::Disconnect, ], :warn => [ - #RuntimeError, - #Net::SSH::AuthenticationFailed, + # RuntimeError, + # Net::SSH::AuthenticationFailed, ], } include Input::CLI def connect node - @node = node + @node = node @node.model.cfg['ftp'].each { |cb| instance_exec(&cb) } @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-ftp", 'w') if Oxidized.config.input.debug? @ftp = Net::FTP.new(@node.ip) @ftp.passive = Oxidized.config.input.ftp.passive - @ftp.login @node.auth[:username], @node.auth[:password] + @ftp.login @node.auth[:username], @node.auth[:password] connected? end @@ -47,10 +47,9 @@ module Oxidized def disconnect @ftp.close - #rescue Errno::ECONNRESET, IOError + # rescue Errno::ECONNRESET, IOError ensure @log.close if Oxidized.config.input.debug? end - end end diff --git a/lib/oxidized/input/ssh.rb b/lib/oxidized/input/ssh.rb index 27e81e0..780bdf2 100644 --- a/lib/oxidized/input/ssh.rb +++ b/lib/oxidized/input/ssh.rb @@ -24,20 +24,24 @@ module Oxidized secure = Oxidized.config.input.ssh.secure @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-ssh", 'w') if Oxidized.config.input.debug? port = vars(:ssh_port) || 22 - + ssh_opts = { - :port => port.to_i, - :password => @node.auth[:password], :timeout => Oxidized.config.timeout, - :paranoid => secure, - :auth_methods => %w(none publickey password keyboard-interactive), - :number_of_password_prompts => 0, - } + port: port.to_i, + paranoid: secure, + keepalive: true, + password: @node.auth[:password], :timeout => Oxidized.config.timeout, + number_of_password_prompts: 0, + } + + auth_methods = vars(:auth_methods) || %w(none publickey password) + ssh_opts[:auth_methods] = auth_methods + Oxidized.logger.debug "AUTH METHODS::#{auth_methods}" if proxy_host = vars(:ssh_proxy) proxy_command = "ssh " proxy_command += "-o StrictHostKeyChecking=no " unless secure proxy_command += "#{proxy_host} -W %h:%p" - proxy = Net::SSH::Proxy::Command.new(proxy_command) + proxy = Net::SSH::Proxy::Command.new(proxy_command) ssh_opts[:proxy] = proxy end @@ -52,7 +56,7 @@ module Oxidized begin login rescue Timeout::Error - raise PromptUndetect, [ @output, 'not matching configured prompt', @node.prompt ].join(' ') + raise PromptUndetect, [@output, 'not matching configured prompt', @node.prompt].join(' ') end end connected? @@ -62,7 +66,7 @@ module Oxidized @ssh and not @ssh.closed? end - def cmd cmd, expect=node.prompt + def cmd cmd, expect = node.prompt Oxidized.logger.debug "lib/oxidized/input/ssh.rb #{cmd} @ #{node.name} with expect: #{expect.inspect}" if @exec @ssh.exec! cmd @@ -100,7 +104,7 @@ module Oxidized ch.on_data do |_ch, data| if Oxidized.config.input.debug? @log.print data - @log.fsync + @log.flush end @output << data @output = @node.model.expects @output @@ -117,19 +121,18 @@ module Oxidized # some models have SSH auth or terminal auth based on version of code # if SSH is configured for terminal auth, we'll still try to detect prompt def login - if @username - match = expect username, @node.prompt - if match == username - cmd @node.auth[:username], password - cmd @node.auth[:password] - end - else - expect @node.prompt + match_re = [@node.prompt] + match_re << @username if @username + match_re << @password if @password + until (match = expect(match_re)) == @node.prompt + cmd(@node.auth[:username], nil) if match == @username + cmd(@node.auth[:password], nil) if match == @password + match_re.delete match end end - def exec state=nil - state == nil ? @exec : (@exec=state) unless vars :ssh_no_exec + def exec state = nil + state == nil ? @exec : (@exec = state) unless vars :ssh_no_exec end def cmd_shell(cmd, expect_re) @@ -152,6 +155,5 @@ module Oxidized end end end - end end diff --git a/lib/oxidized/input/telnet.rb b/lib/oxidized/input/telnet.rb index a5561b9..4b9a656 100644 --- a/lib/oxidized/input/telnet.rb +++ b/lib/oxidized/input/telnet.rb @@ -10,15 +10,16 @@ module Oxidized @node = node @timeout = Oxidized.config.timeout @node.model.cfg['telnet'].each { |cb| instance_exec(&cb) } + @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-telnet", 'w') if Oxidized.config.input.debug? port = vars(:telnet_port) || 23 - opt = { 'Host' => @node.ip, - 'Port' => port.to_i, - 'Timeout' => @timeout, - 'Model' => @node.model } - opt['Output_log'] = Oxidized::Config::Log + "/#{@node.ip}-telnet" if Oxidized.config.input.debug? + telnet_opts = { 'Host' => @node.ip, + 'Port' => port.to_i, + 'Timeout' => @timeout, + 'Model' => @node.model, + 'Log' => @log } - @telnet = Net::Telnet.new opt + @telnet = Net::Telnet.new telnet_opts if @node.auth[:username] and @node.auth[:username].length > 0 expect username @telnet.puts @node.auth[:username] @@ -28,7 +29,7 @@ module Oxidized begin expect @node.prompt rescue Timeout::Error - raise PromptUndetect, [ 'unable to detect prompt:', @node.prompt ].join(' ') + raise PromptUndetect, ['unable to detect prompt:', @node.prompt].join(' ') end end @@ -36,7 +37,7 @@ module Oxidized @telnet and not @telnet.sock.closed? end - def cmd cmd, expect=@node.prompt + def cmd cmd, expect = @node.prompt Oxidized.logger.debug "Telnet: #{cmd} @#{@node.name}" args = { 'String' => cmd } args.merge!({ 'Match' => expect, 'Timeout' => @timeout }) if expect @@ -62,13 +63,14 @@ module Oxidized disconnect_cli @telnet.close rescue Errno::ECONNRESET + ensure + @log.close if Oxidized.config.input.debug? + (@telnet.close rescue true) unless @telnet.sock.closed? end end - end end - class Net::Telnet ## FIXME: we just need 'line = model.expects line' to handle pager ## how to do this, without redefining the whole damn thing @@ -79,6 +81,7 @@ class Net::Telnet waittime = @options["Waittime"] fail_eof = @options["FailEOF"] model = @options["Model"] + @log = @options["Log"] if options.kind_of?(Hash) prompt = if options.has_key?("Match") @@ -86,7 +89,7 @@ class Net::Telnet elsif options.has_key?("Prompt") options["Prompt"] elsif options.has_key?("String") - Regexp.new( Regexp.quote(options["String"]) ) + Regexp.new(Regexp.quote(options["String"])) end time_out = options["Timeout"] if options.has_key?("Timeout") waittime = options["Waittime"] if options.has_key?("Waittime") @@ -102,9 +105,9 @@ class Net::Telnet line = '' buf = '' rest = '' - until(prompt === line and not IO::select([@sock], nil, nil, waittime)) + until prompt === line and not IO::select([@sock], nil, nil, waittime) unless IO::select([@sock], nil, nil, time_out) - raise TimeoutError, "timed out while waiting for more data" + raise Timeout::Error, "timed out while waiting for more data" end begin c = @sock.readpartial(1024 * 1024) @@ -114,32 +117,35 @@ class Net::Telnet c = rest + c if Integer(c.rindex(/#{IAC}#{SE}/no) || 0) < Integer(c.rindex(/#{IAC}#{SB}/no) || 0) - buf = preprocess(c[0 ... c.rindex(/#{IAC}#{SB}/no)]) - rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1] + buf = preprocess(c[0...c.rindex(/#{IAC}#{SB}/no)]) + rest = c[c.rindex(/#{IAC}#{SB}/no)..-1] elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) || c.rindex(/\r\z/no) - buf = preprocess(c[0 ... pt]) - rest = c[pt .. -1] + buf = preprocess(c[0...pt]) + rest = c[pt..-1] else buf = preprocess(c) rest = '' end - else - # Not Telnetmode. - # - # We cannot use preprocess() on this data, because that - # method makes some Telnetmode-specific assumptions. - buf = rest + c - rest = '' - unless @options["Binmode"] - if pt = buf.rindex(/\r\z/no) - buf = buf[0 ... pt] - rest = buf[pt .. -1] - end - buf.gsub!(/#{EOL}/no, "\n") - end + else + # Not Telnetmode. + # + # We cannot use preprocess() on this data, because that + # method makes some Telnetmode-specific assumptions. + buf = rest + c + rest = '' + unless @options["Binmode"] + if pt = buf.rindex(/\r\z/no) + buf = buf[0...pt] + rest = buf[pt..-1] + end + buf.gsub!(/#{EOL}/no, "\n") + end + end + if Oxidized.config.input.debug? + @log.print buf + @log.flush end - @log.print(buf) if @options.has_key?("Output_log") line += buf line = model.expects line line = yield line if block_given? diff --git a/lib/oxidized/jobs.rb b/lib/oxidized/jobs.rb index c566778..fdc1cbf 100644 --- a/lib/oxidized/jobs.rb +++ b/lib/oxidized/jobs.rb @@ -6,7 +6,7 @@ module Oxidized def initialize max, interval, nodes @max = max - # Set interval to 1 if interval is 0 (=disabled) so we don't break + # Set interval to 1 if interval is 0 (=disabled) so we don't break # the 'ceil' function @interval = interval == 0 ? 1 : interval @nodes = nodes @@ -28,7 +28,7 @@ module Oxidized @durations.fill AVERAGE_DURATION, @durations.size...@nodes.size end @durations.push(last).shift - @duration = @durations.inject(:+).to_f / @nodes.size #rolling average + @duration = @durations.inject(:+).to_f / @nodes.size # rolling average new_count end @@ -45,9 +45,8 @@ module Oxidized # and c) there is more than MAX_INTER_JOB_GAP since last one was started # then we want one more thread (rationale is to fix hanging thread causing HOLB) if @want <= size and @want < @nodes.size - @want +=1 if (Time.now.utc - @last) > MAX_INTER_JOB_GAP + @want += 1 if (Time.now.utc - @last) > MAX_INTER_JOB_GAP end end - end end diff --git a/lib/oxidized/manager.rb b/lib/oxidized/manager.rb index bf28ae7..c4523f3 100644 --- a/lib/oxidized/manager.rb +++ b/lib/oxidized/manager.rb @@ -7,11 +7,11 @@ module Oxidized class << self def load dir, file begin - require File.join dir, file+'.rb' + require File.join dir, file + '.rb' klass = nil [Oxidized, Object].each do |mod| klass = mod.constants.find { |const| const.to_s.downcase == file.downcase } - klass = mod.constants.find { |const| const.to_s.downcase == 'oxidized'+ file.downcase } unless klass + klass = mod.constants.find { |const| const.to_s.downcase == 'oxidized' + file.downcase } unless klass klass = mod.const_get klass if klass break if klass end @@ -31,16 +31,19 @@ module Oxidized @source = {} @hook = {} end + def add_input method method = Manager.load Config::InputDir, method return false if method.empty? @input.merge! method end + def add_output method method = Manager.load Config::OutputDir, method return false if method.empty? @output.merge! method end + def add_model _model name = _model _model = Manager.load File.join(Config::Root, 'model'), name @@ -48,14 +51,16 @@ module Oxidized return false if _model.empty? @model.merge! _model end + def add_source _source - return nil if @source.key? _source + return nil if @source.has_key? _source _source = Manager.load Config::SourceDir, _source return false if _source.empty? @source.merge! _source end + def add_hook _hook - return nil if @hook.key? _hook + return nil if @hook.has_key? _hook name = _hook _hook = Manager.load File.join(Config::Root, 'hook'), name _hook = Manager.load Config::HookDir, name if _hook.empty? diff --git a/lib/oxidized/model/acos.rb b/lib/oxidized/model/acos.rb index 47649a2..a2db89c 100644 --- a/lib/oxidized/model/acos.rb +++ b/lib/oxidized/model/acos.rb @@ -3,7 +3,7 @@ class ACOS < Oxidized::Model comment '! ' - ##ACOS prompt changes depending on the state of the device + # ACOS prompt changes depending on the state of the device prompt /^([-\w.\/:?\[\]\(\)]+[#>]\s?)$/ cmd :secret do |cfg| @@ -30,19 +30,19 @@ class ACOS < Oxidized::Model end cmd 'show partition-config all' do |cfg| - cfg.gsub! /(Current configuration).*/, '\\1 <removed>' - cfg.gsub! /(Configuration last updated at).*/, '\\1 <removed>' - cfg.gsub! /(Configuration last saved at).*/, '\\1 <removed>' - cfg.gsub! /(Configuration last synchronized at).*/, '\\1 <removed>' - cfg - end + cfg.gsub! /(Current configuration).*/, '\\1 <removed>' + cfg.gsub! /(Configuration last updated at).*/, '\\1 <removed>' + cfg.gsub! /(Configuration last saved at).*/, '\\1 <removed>' + cfg.gsub! /(Configuration last synchronized at).*/, '\\1 <removed>' + cfg + end cmd 'show running-config all-partitions' do |cfg| - cfg.gsub! /(Current configuration).*/, '\\1 <removed>' - cfg.gsub! /(Configuration last updated at).*/, '\\1 <removed>' - cfg.gsub! /(Configuration last saved at).*/, '\\1 <removed>' - cfg.gsub! /(Configuration last synchronized at).*/, '\\1 <removed>' - cfg + cfg.gsub! /(Current configuration).*/, '\\1 <removed>' + cfg.gsub! /(Configuration last updated at).*/, '\\1 <removed>' + cfg.gsub! /(Configuration last saved at).*/, '\\1 <removed>' + cfg.gsub! /(Configuration last synchronized at).*/, '\\1 <removed>' + cfg end cmd 'show aflex all-partitions' do |cfg| @@ -50,7 +50,7 @@ class ACOS < Oxidized::Model end cmd 'show aflex all-partitions' do |cfg| - @partitions_aflex = cfg.lines.each_with_object({}) do |l,h| + @partitions_aflex = cfg.lines.each_with_object({}) do |l, h| h[$1] = [] if l.match /partition: (.+)/ # only consider scripts that have passed syntax check h[h.keys.last] << $1 if l.match /^([\w-]+) +Check/ @@ -66,7 +66,7 @@ class ACOS < Oxidized::Model pre do unless @partitions_aflex.empty? out = [] - @partitions_aflex.each do |partition,arules| + @partitions_aflex.each do |partition, arules| out << "! partition: #{partition}" arules.each do |name| cmd("show aflex #{name} partition #{partition}") do |cfg| @@ -85,7 +85,7 @@ class ACOS < Oxidized::Model username /login:/ password /^Password:/ end - + cfg :telnet, :ssh do # preferred way to handle additional passwords post_login do @@ -98,5 +98,4 @@ class ACOS < Oxidized::Model post_login 'terminal width 0' pre_logout "exit\nexit\nY\r\n" end - end diff --git a/lib/oxidized/model/acsw.rb b/lib/oxidized/model/acsw.rb index 1aee2b6..c0857b3 100644 --- a/lib/oxidized/model/acsw.rb +++ b/lib/oxidized/model/acsw.rb @@ -1,5 +1,4 @@ class ACSW < Oxidized::Model - prompt /([\w.@()\/\\-]+[#>]\s?)/ comment '! ' @@ -25,16 +24,13 @@ class ACSW < Oxidized::Model cfg end - cmd 'show version' do |cfg| comment cfg end - - cmd 'show inventory' do |cfg| - comment cfg - end - + cmd 'show inventory' do |cfg| + comment cfg + end cmd 'show running-config' do |cfg| cfg = cfg.each_line.to_a[3..-1] @@ -63,5 +59,4 @@ class ACSW < Oxidized::Model post_login 'terminal length 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/aen.rb b/lib/oxidized/model/aen.rb index 6d87433..474e6d5 100644 --- a/lib/oxidized/model/aen.rb +++ b/lib/oxidized/model/aen.rb @@ -16,5 +16,4 @@ class AEN < Oxidized::Model cfg :ssh do pre_logout 'exit' end - -end
\ No newline at end of file +end diff --git a/lib/oxidized/model/aireos.rb b/lib/oxidized/model/aireos.rb index ba13120..a0378c7 100644 --- a/lib/oxidized/model/aireos.rb +++ b/lib/oxidized/model/aireos.rb @@ -1,17 +1,16 @@ class Aireos < Oxidized::Model - # AireOS (at least I think that is what it's called, hard to find data) # Used in Cisco WLC 5500 - comment '# ' ## this complains too, can't find real comment char + comment '# ' # this complains too, can't find real comment char prompt /^\([^\)]+\)\s>/ cmd :all do |cfg| cfg.each_line.to_a[1..-2].join end - ##show sysinfo? - ##show switchconfig? + # show sysinfo? + # show switchconfig? cmd 'show udi' do |cfg| cfg = comment clean cfg @@ -51,5 +50,4 @@ class Aireos < Oxidized::Model out = out.join "\n" out << "\n" end - end diff --git a/lib/oxidized/model/alteonos.rb b/lib/oxidized/model/alteonos.rb index 9eacf4e..dec4faf 100644 --- a/lib/oxidized/model/alteonos.rb +++ b/lib/oxidized/model/alteonos.rb @@ -1,5 +1,4 @@ class ALTEONOS < Oxidized::Model - prompt /^\(?.+\)?\s?[#>]/ comment '! ' @@ -11,19 +10,19 @@ class ALTEONOS < Oxidized::Model cfg end - ############################################################################################## - ## Added to remove # - ## # - ##/* Configuration dump taken 14:10:20 Fri Jul 28, 2017 (DST) # - ##/* Configuration last applied at 16:17:05 Fri Jul 14, 2017 # - ##/* Configuration last save at 16:17:43 Fri Jul 14, 2017 # - ##/* Version 29.0.3.12, vXXXXXXXX, Base MAC address XXXXXXXXXXX # - ##/* To restore SSL Offloading configuration and management HTTPS access, # - ##/* it is recommended to include the private keys in the dump. # - ## OR # - ##/* To restore SSL Offloading configuration and management HTTPS access,it is recommended # - ##/* to include the private keys in the dump. # - ## # + ############################################################################################## + # Added to remove # + # # + # /* Configuration dump taken 14:10:20 Fri Jul 28, 2017 (DST) # + # /* Configuration last applied at 16:17:05 Fri Jul 14, 2017 # + # /* Configuration last save at 16:17:43 Fri Jul 14, 2017 # + # /* Version 29.0.3.12, vXXXXXXXX, Base MAC address XXXXXXXXXXX # + # /* To restore SSL Offloading configuration and management HTTPS access, # + # /* it is recommended to include the private keys in the dump. # + # OR # + # /* To restore SSL Offloading configuration and management HTTPS access,it is recommended # + # /* to include the private keys in the dump. # + # # ############################################################################################## cmd 'cfg/dump' do |cfg| @@ -35,19 +34,19 @@ class ALTEONOS < Oxidized::Model cfg end - #Answer for Dispay private keys + # Answer for Dispay private keys expect /^Display private keys\?\s?\[y\/n\]\: $/ do |data, re| send "n\r" data.sub re, '' end - #Answer for sync to peer on exit + # Answer for sync to peer on exit expect /^Confirm Sync to Peer\s?\[y\/n\]\: $/ do |data, re| send "n\r" data.sub re, '' end - #Answer for Unsaved configuration + # Answer for Unsaved configuration expect /^(WARNING: There are unsaved configuration changes).*/ do |data, re| send "n\r" data.sub re, '' @@ -56,5 +55,4 @@ class ALTEONOS < Oxidized::Model cfg :ssh do pre_logout 'exit' end - end diff --git a/lib/oxidized/model/alvarion.rb b/lib/oxidized/model/alvarion.rb index 7a4dcc7..8831f49 100644 --- a/lib/oxidized/model/alvarion.rb +++ b/lib/oxidized/model/alvarion.rb @@ -1,5 +1,4 @@ class Alvarion < Oxidized::Model - # Used in Alvarion wisp equipment # Run this command as an instance of Model so we can access node @@ -7,9 +6,6 @@ class Alvarion < Oxidized::Model cmd "#{node.auth[:password]}.cfg" end - cfg :tftp do - end - end diff --git a/lib/oxidized/model/aos.rb b/lib/oxidized/model/aos.rb index ec73b92..fed78c8 100644 --- a/lib/oxidized/model/aos.rb +++ b/lib/oxidized/model/aos.rb @@ -1,8 +1,7 @@ class AOS < Oxidized::Model - # Alcatel-Lucent Operating System # used in OmniSwitch - + comment '! ' cmd :all do |cfg| @@ -10,7 +9,7 @@ class AOS < Oxidized::Model end cmd 'show system' do |cfg| - cfg = cfg.each_line.find{|line|line.match 'Description'} + cfg = cfg.each_line.find { |line| line.match 'Description' } comment cfg.to_s.strip end @@ -34,5 +33,4 @@ class AOS < Oxidized::Model cfg :telnet, :ssh do pre_logout 'exit' end - end diff --git a/lib/oxidized/model/aos7.rb b/lib/oxidized/model/aos7.rb index 8d11066..00bee54 100644 --- a/lib/oxidized/model/aos7.rb +++ b/lib/oxidized/model/aos7.rb @@ -1,8 +1,7 @@ class AOS7 < Oxidized::Model - # Alcatel-Lucent Operating System Version 7 (Linux based) # used in OmniSwitch 6900/10k - + comment '! ' cmd :all do |cfg, cmdstring| @@ -11,7 +10,7 @@ class AOS7 < Oxidized::Model end cmd 'show system' do |cfg| - cfg = cfg.each_line.find{|line|line.match 'Description'} + cfg = cfg.each_line.find { |line| line.match 'Description' } comment cfg.to_s.strip + "\n" end diff --git a/lib/oxidized/model/aosw.rb b/lib/oxidized/model/aosw.rb index 71fde2e..7543353 100644 --- a/lib/oxidized/model/aosw.rb +++ b/lib/oxidized/model/aosw.rb @@ -1,14 +1,13 @@ class AOSW < Oxidized::Model - # AOSW Aruba Wireless, IAP, Instant Controller and Mobility Access Switches # Used in Alcatel OAW-4750 WLAN controller # Also Dell controllers - + # HPE Aruba Switches should use a different model as the software is based on the HP Procurve line. - + # Support for IAP & Instant Controller tested with 115, 205, 215 & 325 running 6.4.4.8-4.2.4.5_57965 # Support for Mobility Access Switches tested with S2500-48P & S2500-24P running 7.4.1.4_54199 and S2500-24P running 7.4.1.7_57823 - # All IAPs connected to a Instant Controller will have the same config output. Only the controller needs to be monitored. + # All IAPs connected to a Instant Controller will have the same config output. Only the controller needs to be monitored. comment '# ' prompt /^\(?.+\)?\s[#>]/ @@ -26,11 +25,11 @@ class AOSW < Oxidized::Model cfg.gsub!(/ sha (\S+)/, ' sha <secret removed>') cfg.gsub!(/ des (\S+)/, ' des <secret removed>') cfg.gsub!(/mobility-manager (\S+) user (\S+) (\S+)/, 'mobility-manager \1 user \2 <secret removed>') - cfg.gsub!(/mgmt-user (\S+) (root|guest\-provisioning|network\-operations|read\-only|location\-api\-mgmt) (\S+)$/, 'mgmt-user \1 \2 <secret removed>') #MAS & Wireless Controler - cfg.gsub!(/mgmt-user (\S+) (\S+)( (read\-only|guest\-mgmt))?$/, 'mgmt-user \1 <secret removed> \3') #IAP -#MAS format: mgmt-user <username> <accesslevel> <password hash> -#IAP format (root user): mgmt-user <username> <password hash> -#IAP format: mgmt-user <username> <password hash> <access level> + cfg.gsub!(/mgmt-user (\S+) (root|guest\-provisioning|network\-operations|read\-only|location\-api\-mgmt) (\S+)$/, 'mgmt-user \1 \2 <secret removed>') # MAS & Wireless Controler + cfg.gsub!(/mgmt-user (\S+) (\S+)( (read\-only|guest\-mgmt))?$/, 'mgmt-user \1 <secret removed> \3') # IAP + # MAS format: mgmt-user <username> <accesslevel> <password hash> + # IAP format (root user): mgmt-user <username> <password hash> + # IAP format: mgmt-user <username> <password hash> <access level> cfg.gsub!(/key (\S+)$/, 'key <secret removed>') cfg.gsub!(/wpa-passphrase (\S+)$/, 'wpa-passphrase <secret removed>') cfg.gsub!(/bkup-passwords (\S+)$/, 'bkup-passwords <secret removed>') @@ -40,22 +39,22 @@ class AOSW < Oxidized::Model end cmd 'show version' do |cfg| - cfg = cfg.each_line.select { |line| not line.match /(Switch|AP) uptime/i } + cfg = cfg.each_line.reject { |line| line.match /(Switch|AP) uptime/i } rstrip_cfg comment cfg.join end cmd 'show inventory' do |cfg| - cfg = "" if cfg.match /(Invalid input detected at '\^' marker|Parse error)/ #Don't show for unsupported devices (IAP and MAS) + cfg = "" if cfg.match /(Invalid input detected at '\^' marker|Parse error)/ # Don't show for unsupported devices (IAP and MAS) rstrip_cfg clean cfg end cmd 'show slots' do |cfg| - cfg = "" if cfg.match /(Invalid input detected at '\^' marker|Parse error)/ #Don't show for unsupported devices (IAP and MAS) + cfg = "" if cfg.match /(Invalid input detected at '\^' marker|Parse error)/ # Don't show for unsupported devices (IAP and MAS) rstrip_cfg comment cfg end cmd 'show license' do |cfg| - cfg = "" if cfg.match /(Invalid input detected at '\^' marker|Parse error)/ #Don't show for unsupported devices (IAP and MAS) + cfg = "" if cfg.match /(Invalid input detected at '\^' marker|Parse error)/ # Don't show for unsupported devices (IAP and MAS) rstrip_cfg comment cfg end @@ -112,5 +111,4 @@ class AOSW < Oxidized::Model out = comment out.join "\n" out << "\n" end - end diff --git a/lib/oxidized/model/apc_aos.rb b/lib/oxidized/model/apc_aos.rb index 530d436..5a4d232 100644 --- a/lib/oxidized/model/apc_aos.rb +++ b/lib/oxidized/model/apc_aos.rb @@ -1,11 +1,8 @@ class Apc_aos < Oxidized::Model - cmd 'config.ini' do |cfg| cfg.gsub! /^; Configuration file\, generated on.*/, '' end cfg :ftp do end - end - diff --git a/lib/oxidized/model/arbos.rb b/lib/oxidized/model/arbos.rb index 389f3f6..51b269d 100644 --- a/lib/oxidized/model/arbos.rb +++ b/lib/oxidized/model/arbos.rb @@ -1,9 +1,8 @@ -class ARBOS < Oxidized::Model - +class ARBOS < Oxidized::Model # Arbor OS model # prompt /^[\S\s]+\n([\w.@-]+[:\/#>]+)\s?$/ - comment '# ' + comment '# ' cmd 'system hardware' do |cfg| cfg.gsub! /^Boot\ time\:\s.+/, '' # Remove boot timer diff --git a/lib/oxidized/model/aricentiss.rb b/lib/oxidized/model/aricentiss.rb index 8821801..77b78f4 100644 --- a/lib/oxidized/model/aricentiss.rb +++ b/lib/oxidized/model/aricentiss.rb @@ -4,8 +4,7 @@ # 0 SSE-G48-TG4 (P2-01) 1.0.16-9 class AricentISS < Oxidized::Model - - prompt (/^(\e\[27m)?[ \r]*\w+# ?$/) + prompt (/^(\e\[27m)?[ \r]*[\w-]+# ?$/) cfg :ssh do # "pagination" was misspelled in some (earlier) versions (at least 1.0.16-9) @@ -49,5 +48,4 @@ class AricentISS < Oxidized::Model l }.join.gsub(/ +$/, '') end - end diff --git a/lib/oxidized/model/asa.rb b/lib/oxidized/model/asa.rb index 9df4206..dfd94b1 100644 --- a/lib/oxidized/model/asa.rb +++ b/lib/oxidized/model/asa.rb @@ -1,5 +1,4 @@ class ASA < Oxidized::Model - # Cisco ASA model # # Only SSH supported for the sake of security @@ -27,7 +26,7 @@ class ASA < Oxidized::Model cmd 'show version' do |cfg| # avoid commits due to uptime / ixo-router01 up 2 mins 28 secs / ixo-router01 up 1 days 2 hours - cfg = cfg.each_line.select { |line| not line.match /(\s+up\s+\d+\s+)|(.*days.*)/ } + cfg = cfg.each_line.reject { |line| line.match /(\s+up\s+\d+\s+)|(.*days.*)/ } cfg = cfg.join comment cfg end @@ -54,48 +53,47 @@ class ASA < Oxidized::Model post_login 'terminal pager 0' pre_logout 'exit' end - + def single_context - # Single context mode - cmd 'more system:running-config' do |cfg| - cfg = cfg.each_line.to_a[3..-1].join - cfg.gsub! /^: [^\n]*\n/, '' - # backup any xml referenced in the configuration. - anyconnect_profiles = cfg.scan(Regexp.new('(\sdisk0:/.+\.xml)')).flatten - anyconnect_profiles.each do |profile| - cfg << (comment profile + "\n" ) - cmd ("more" + profile) do |xml| - cfg << (comment xml) - end + # Single context mode + cmd 'more system:running-config' do |cfg| + cfg = cfg.each_line.to_a[3..-1].join + cfg.gsub! /^: [^\n]*\n/, '' + # backup any xml referenced in the configuration. + anyconnect_profiles = cfg.scan(Regexp.new('(\sdisk0:/.+\.xml)')).flatten + anyconnect_profiles.each do |profile| + cfg << (comment profile + "\n") + cmd ("more" + profile) do |xml| + cfg << (comment xml) end - # if DAP is enabled, also backup dap.xml - if cfg.rindex(/dynamic-access-policy-record\s(?!DfltAccessPolicy)/) - cfg << (comment "disk0:/dap.xml\n") - cmd "more disk0:/dap.xml" do |xml| - cfg << (comment xml) - end + end + # if DAP is enabled, also backup dap.xml + if cfg.rindex(/dynamic-access-policy-record\s(?!DfltAccessPolicy)/) + cfg << (comment "disk0:/dap.xml\n") + cmd "more disk0:/dap.xml" do |xml| + cfg << (comment xml) end - cfg end + cfg + end end def multiple_context - # Multiple context mode - cmd 'changeto system' do |cfg| - cmd 'show running-config' do |systemcfg| - allcfg = "\n\n" + systemcfg + "\n\n" - contexts = systemcfg.scan(/^context (\S+)$/) - files = systemcfg.scan(/config-url (\S+)$/) - contexts.each_with_index do |cont, i| - allcfg = allcfg + "\n\n----------========== [ CONTEXT " + cont.join(" ") + " FILE " + files[i].join(" ") + " ] ==========----------\n\n" - cmd "more " + files[i].join(" ") do |cfgcontext| - allcfg = allcfg + "\n\n" + cfgcontext - end + # Multiple context mode + cmd 'changeto system' do |cfg| + cmd 'show running-config' do |systemcfg| + allcfg = "\n\n" + systemcfg + "\n\n" + contexts = systemcfg.scan(/^context (\S+)$/) + files = systemcfg.scan(/config-url (\S+)$/) + contexts.each_with_index do |cont, i| + allcfg = allcfg + "\n\n----------========== [ CONTEXT " + cont.join(" ") + " FILE " + files[i].join(" ") + " ] ==========----------\n\n" + cmd "more " + files[i].join(" ") do |cfgcontext| + allcfg = allcfg + "\n\n" + cfgcontext end - cfg = allcfg end - cfg + cfg = allcfg end + cfg + end end - end diff --git a/lib/oxidized/model/asyncos.rb b/lib/oxidized/model/asyncos.rb index 875690b..9e4d10e 100644 --- a/lib/oxidized/model/asyncos.rb +++ b/lib/oxidized/model/asyncos.rb @@ -1,49 +1,46 @@ class AsyncOS < Oxidized::Model + # ESA prompt "(mail.example.com)> " or "mail.example.com> " + prompt /^\r*([(]?[\w. ]+[)]?[#>]\s+)$/ + comment '! ' - # ESA prompt "(mail.example.com)> " - prompt /^\r*([(][\w. ]+[)][#>]\s+)$/ - comment '! ' - - # Select passphrase display option - expect /\[\S+\]>\s/ do |data, re| - send "3\n" - data.sub re, '' - end - - # handle paging - expect /-Press Any Key For More-+.*$/ do |data, re| - send " " - data.sub re, '' - end - - cmd 'version' do |cfg| - comment cfg - end + # Select passphrase display option + expect /\[\S+\]>\s/ do |data, re| + send "3\n" + data.sub re, '' + end - cmd 'showconfig' do |cfg| - #Delete hour and date which change each run - #cfg.gsub! /\sCurrent Time: \S+\s\S+\s+\S+\s\S+\s\S+/, ' Current Time:' - # Delete select passphrase display option - cfg.gsub! /Choose the passphrase option:/, '' - cfg.gsub! /1. Mask passphrases \(Files with masked passphrases cannot be loaded using/, '' - cfg.gsub! /loadconfig command\)/, '' - cfg.gsub! /2. Encrypt passphrases/, '' - cfg.gsub! /3. Plain passphrases/, '' - cfg.gsub! /^3$/, '' - #Delete space - cfg.gsub! /\n\s{25,26}/, '' - #Delete after line - cfg.gsub! /([-\\\/,.\w><@]+)(\s{25,27})/,"\\1" - # Add a carriage return - cfg.gsub! /([-\\\/,.\w><@]+)(\s{6})([-\\\/,.\w><@]+)/,"\\1\n\\2\\3" - # Delete prompt - cfg.gsub! /^\r*([(][\w. ]+[)][#>]\s+)$/, '' - cfg + # handle paging + expect /-Press Any Key For More-+.*$/ do |data, re| + send " " + data.sub re, '' + end - end - - cfg :ssh do - pre_logout "exit" - end - + cmd 'version' do |cfg| + comment cfg + end + + cmd 'showconfig' do |cfg| + # Delete hour and date which change each run + # cfg.gsub! /\sCurrent Time: \S+\s\S+\s+\S+\s\S+\s\S+/, ' Current Time:' + # Delete select passphrase display option + cfg.gsub! /Choose the passphrase option:/, '' + cfg.gsub! /1. Mask passphrases \(Files with masked passphrases cannot be loaded using/, '' + cfg.gsub! /loadconfig command\)/, '' + cfg.gsub! /2. Encrypt passphrases/, '' + cfg.gsub! /3. Plain passphrases/, '' + cfg.gsub! /^3$/, '' + # Delete space + cfg.gsub! /\n\s{25,26}/, '' + # Delete after line + cfg.gsub! /([-\\\/,.\w><@]+)(\s{25,27})/, "\\1" + # Add a carriage return + cfg.gsub! /([-\\\/,.\w><@]+)(\s{6})([-\\\/,.\w><@]+)/, "\\1\n\\2\\3" + # Delete prompt + cfg.gsub! /^\r*([(][\w. ]+[)][#>]\s+)$/, '' + cfg + end + + cfg :ssh do + pre_logout "exit" + end end diff --git a/lib/oxidized/model/audiocodes.rb b/lib/oxidized/model/audiocodes.rb index b7ee70e..2c77abb 100644 --- a/lib/oxidized/model/audiocodes.rb +++ b/lib/oxidized/model/audiocodes.rb @@ -1,20 +1,17 @@ class AudioCodes < Oxidized::Model - -# Pull config from AudioCodes Mediant devices from version > 7.0 + # Pull config from AudioCodes Mediant devices from version > 7.0 prompt /^\r?([\w.@() -]+[#>]\s?)$/ - comment '## ' + comment '## ' expect /\s*--MORE--$/ do |data, re| - send ' ' data.sub re, '' - end cmd 'show running-config' do |cfg| - cfg + cfg end cfg :ssh do @@ -22,11 +19,10 @@ class AudioCodes < Oxidized::Model password /^.+password:\s$/ pre_logout 'exit' end - + cfg :telnet do username /^Username:\s$/ password /^Password:\s$/ pre_logout 'exit' end - end diff --git a/lib/oxidized/model/awplus.rb b/lib/oxidized/model/awplus.rb index 1d8fbcd..7c88d60 100644 --- a/lib/oxidized/model/awplus.rb +++ b/lib/oxidized/model/awplus.rb @@ -1,27 +1,26 @@ class AWPlus < Oxidized::Model + # Allied Telesis Alliedware Plus Model# + # https://www.alliedtelesis.com/products/software/AlliedWare-Plus - #Allied Telesis Alliedware Plus Model# - #https://www.alliedtelesis.com/products/software/AlliedWare-Plus - prompt /^(\r?[\w.@:\/-]+[#>]\s?)$/ - comment '! ' + comment '! ' - #Avoids needing "term length 0" to display full config file. - expect /--More--/ do |data, re| - send ' ' - data.sub re, '' - end + # Avoids needing "term length 0" to display full config file. + expect /--More--/ do |data, re| + send ' ' + data.sub re, '' + end - #Removes gibberish pager output e.g. VT100 escape codes + # Removes gibberish pager output e.g. VT100 escape codes cmd :all do |cfg| cfg.gsub! /\e\[K/, '' # example how to handle pager - cleareol EL0 cfg.gsub! /\e\[7m\e\[m/, '' # example how to handle pager - Reverse SGR7 - cfg.gsub! /\r/, '' # Filters rogue ^M - see issue #415 + cfg.gsub! /\r/, '' # Filters rogue ^M - see issue #415 cfg.each_line.to_a[1..-2].join end - #Remove passwords from config file. - #Add vars "remove_secret: true" to global oxidized config file to enable. + # Remove passwords from config file. + # Add vars "remove_secret: true" to global oxidized config file to enable. cmd :secret do |cfg| cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' @@ -34,52 +33,52 @@ class AWPlus < Oxidized::Model cfg end - #Adds "Show system" output to start of config. + # Adds "Show system" output to start of config. cmd 'Show System' do |cfg| - comment cfg.insert(0,"--------------------------------------------------------------------------------! \n") - #Unhash below to write a comment in the config file. - cfg.insert(0,"Starting: Show system cmd \n") + comment cfg.insert(0, "--------------------------------------------------------------------------------! \n") + # Unhash below to write a comment in the config file. + cfg.insert(0, "Starting: Show system cmd \n") cfg << "\n \nEnding: show system cmd" comment cfg << "\n--------------------------------------------------------------------------------! \n \n" - #Removes the following lines from "show system" in output file. This ensures oxidized diffs are meaningful. - comment cfg.each_line.reject { |line| - line.match /^$\n/ or #Remove blank lines in "sh sys" - line.match /System Status\s*.*/ or - line.match /RAM\s*:.*/ or - line.match /Uptime\s*:.*/ or - line.match /Flash\s*:.*/ or - line.match /Current software\s*:.*/ or - line.match /Software version\s*:.*/ or - line.match /Build date\s*:.*/ }.join + # Removes the following lines from "show system" in output file. This ensures oxidized diffs are meaningful. + comment cfg.each_line.reject { |line| + line.match /^$\n/ or # Remove blank lines in "sh sys" + line.match /System Status\s*.*/ or + line.match /RAM\s*:.*/ or + line.match /Uptime\s*:.*/ or + line.match /Flash\s*:.*/ or + line.match /Current software\s*:.*/ or + line.match /Software version\s*:.*/ or + line.match /Build date\s*:.*/ + } .join end - - #Actually get the devices running config# + + # Actually get the devices running config# cmd 'show running-config' do |cfg| cfg end - - #Config required for telnet to detect username prompt + + # Config required for telnet to detect username prompt cfg :telnet do username /login:\s/ - end + end - #Main login config - cfg :telnet, :ssh do + # Main login config + cfg :telnet, :ssh do post_login do if vars :enable send "enable\n" expect /^Password:\s/ cmd vars(:enable) + "\r\n" else - cmd 'enable' # Required for Priv-Exec users without enable PW to be put into "enable mode". + cmd 'enable' # Required for Priv-Exec users without enable PW to be put into "enable mode". end -# cmd 'terminal length 0' #set so the entire config is output without intervention. + # cmd 'terminal length 0' #set so the entire config is output without intervention. end pre_logout do -# cmd 'terminal no length' #Sets term length back to default on exit. - send "exit\r\n" + # cmd 'terminal no length' #Sets term length back to default on exit. + send "exit\r\n" end - end - + end end diff --git a/lib/oxidized/model/boss.rb b/lib/oxidized/model/boss.rb index 02201a1..0adf4c0 100644 --- a/lib/oxidized/model/boss.rb +++ b/lib/oxidized/model/boss.rb @@ -1,5 +1,5 @@ class Boss < Oxidized::Model - # Avaya Baystack Operating System Software(BOSS) + # Extreme Baystack Operating System Software(BOSS) # Created by danielcoxman@gmail.com # May 15, 2017 # This was tested on ers3510, ers5530, ers4850, ers5952 @@ -16,7 +16,7 @@ class Boss < Oxidized::Model data.sub re, '' end - # Handle the Failed retries since last login + # Handle the Failed retries since last login # no known way to disable other than to implement radius authentication expect /Press ENTER to continue/ do |data, re| send "\n" @@ -28,8 +28,10 @@ class Boss < Oxidized::Model expect /ommand Line Interface\.\.\./ do |data, re| send "c" data.sub re, '' + send "\n" + data.sub re, '' end - + # needed for proper formatting cmd('') { |cfg| comment "#{cfg}\n" } @@ -43,7 +45,7 @@ class Boss < Oxidized::Model cfg.gsub! /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} .*/, '' comment "#{cfg}\n" end - + # if a stack then collect the stacking information cmd 'show stack-info' do |cfg| if @stack @@ -72,5 +74,4 @@ class Boss < Oxidized::Model post_login 'terminal length 0' post_login 'terminal width 132' end - end diff --git a/lib/oxidized/model/br6910.rb b/lib/oxidized/model/br6910.rb index df93793..1e79da3 100644 --- a/lib/oxidized/model/br6910.rb +++ b/lib/oxidized/model/br6910.rb @@ -1,45 +1,43 @@ -
-class BR6910 < Oxidized::Model
-
- prompt /^([\w.@()-]+[#>]\s?)$/
- comment '! '
-
- # not possible to disable paging prior to show running-config
- expect /^((.*)Others to exit ---(.*))$/ do |data, re|
- send 'a'
- data.sub re, ''
- end
-
- cmd :all do |cfg|
- # sometimes br6910s inserts arbitrary whitespace after commands are
- # issued on the CLI, from run to run. this normalises the output.
- cfg.each_line.to_a[1..-2].drop_while { |e| e.match /^\s+$/ }.join
- end
-
- cmd 'show version' do |cfg|
- comment cfg
- end
-
- # show flash is not possible on a brocade 6910, do dir instead
- # to see flash contents (includes config file names)
- cmd 'dir' do |cfg|
- comment cfg
- end
-
- cmd 'show running-config' do |cfg|
- arr = cfg.each_line.to_a
- arr[2..-1].join unless arr.length < 2
- end
-
- cfg :telnet do
- username /^Username:/
- password /^Password:/
- end
-
- # post login and post logout
- cfg :telnet, :ssh do
- post_login ''
- pre_logout 'exit'
- end
-
-end
+ +class BR6910 < Oxidized::Model + prompt /^([\w.@()-]+[#>]\s?)$/ + comment '! ' + + # not possible to disable paging prior to show running-config + expect /^((.*)Others to exit ---(.*))$/ do |data, re| + send 'a' + data.sub re, '' + end + + cmd :all do |cfg| + # sometimes br6910s inserts arbitrary whitespace after commands are + # issued on the CLI, from run to run. this normalises the output. + cfg.each_line.to_a[1..-2].drop_while { |e| e.match /^\s+$/ }.join + end + + cmd 'show version' do |cfg| + comment cfg + end + + # show flash is not possible on a brocade 6910, do dir instead + # to see flash contents (includes config file names) + cmd 'dir' do |cfg| + comment cfg + end + + cmd 'show running-config' do |cfg| + arr = cfg.each_line.to_a + arr[2..-1].join unless arr.length < 2 + end + + cfg :telnet do + username /^Username:/ + password /^Password:/ + end + + # post login and post logout + cfg :telnet, :ssh do + post_login '' + pre_logout 'exit' + end +end diff --git a/lib/oxidized/model/c4cmts.rb b/lib/oxidized/model/c4cmts.rb index 150029c..8ea27c6 100644 --- a/lib/oxidized/model/c4cmts.rb +++ b/lib/oxidized/model/c4cmts.rb @@ -1,15 +1,14 @@ class C4CMTS < Oxidized::Model - # Arris C4 CMTS prompt /^([\w.@:\/-]+[#>]\s?)$/ comment '! ' cmd :all do |cfg| - cfg.each_line.to_a[1..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" + cfg.each_line.to_a[1..-2].map { |line| line.delete("\r").rstrip }.join("\n") + "\n" end - cmd :secret do |cfg| + cmd :secret do |cfg| cfg.gsub! /(.+)\s+encrypted-password\s+\w+\s+(.*)/, '\\1 <secret hidden> \\2' cfg.gsub! /(snmp-server community)\s+".*"\s+(.*)/, '\\1 <secret hidden> \\2' cfg.gsub! /(tacacs.*\s+key)\s+".*"\s+(.*)/, '\\1 <secret hidden> \\2' @@ -25,7 +24,7 @@ class C4CMTS < Oxidized::Model cmd 'show version' do |cfg| # remove uptime readings at char 55 and beyond - cfg = cfg.each_line.map{|line|line.rstrip.slice(0..54)}.join("\n") + "\n" + cfg = cfg.each_line.map { |line| line.rstrip.slice(0..54) }.join("\n") + "\n" comment cfg end @@ -48,5 +47,4 @@ class C4CMTS < Oxidized::Model end pre_logout 'exit' end - end diff --git a/lib/oxidized/model/catos.rb b/lib/oxidized/model/catos.rb index bac9eec..e97a0b6 100644 --- a/lib/oxidized/model/catos.rb +++ b/lib/oxidized/model/catos.rb @@ -1,5 +1,4 @@ class Catos < Oxidized::Model - prompt /^[\w.@-]+>\s?(\(enable\) )?$/ comment '# ' @@ -39,5 +38,4 @@ class Catos < Oxidized::Model end pre_logout 'exit' end - end diff --git a/lib/oxidized/model/cisconga.rb b/lib/oxidized/model/cisconga.rb index 73fb51c..9764351 100644 --- a/lib/oxidized/model/cisconga.rb +++ b/lib/oxidized/model/cisconga.rb @@ -1,5 +1,4 @@ class CiscoNGA < Oxidized::Model - comment '# ' prompt /([\w.@-]+[#>]\s?)$/ @@ -10,10 +9,9 @@ class CiscoNGA < Oxidized::Model cmd 'show configuration' do |cfg| cfg end - + cfg :ssh do post_login 'terminal length 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/ciscosma.rb b/lib/oxidized/model/ciscosma.rb index a52e38a..5a34f86 100644 --- a/lib/oxidized/model/ciscosma.rb +++ b/lib/oxidized/model/ciscosma.rb @@ -1,45 +1,42 @@ class CiscoSMA < Oxidized::Model + # SMA prompt "mail.example.com> " + prompt /^\r*([-\w. ]+\.[-\w. ]+\.[-\w. ]+[#>]\s+)$/ + comment '! ' - # SMA prompt "mail.example.com> " - prompt /^\r*([-\w. ]+\.[-\w. ]+\.[-\w. ]+[#>]\s+)$/ - comment '! ' - - # Select passphrase display option - expect /using loadconfig command\. \[Y\]\>/ do |data, re| - send "y\n" - data.sub re, '' - end - - # handle paging - expect /-Press Any Key For More-+.*$/ do |data, re| - send " " - data.sub re, '' - end - - cmd 'version' do |cfg| - comment cfg - end + # Select passphrase display option + expect /using loadconfig command\. \[Y\]\>/ do |data, re| + send "y\n" + data.sub re, '' + end - cmd 'showconfig' do |cfg| - #Delete hour and date which change each run - #cfg.gsub! /\sCurrent Time: \S+\s\S+\s+\S+\s\S+\s\S+/, ' Current Time:' - # Delete select passphrase display option - cfg.gsub! /Do you want to mask the password\? Files with masked passwords cannot be loaded/, '' - cfg.gsub! /^\s+y/, '' - # Delete space - cfg.gsub! /\n\s{25}/, '' - # Delete after line - cfg.gsub! /([\/\-,.\w><@]+)(\s{27})/,"\\1" - # Add a carriage return - cfg.gsub! /([\/\-,.\w><@]+)(\s{6,8})([\/\-,.\w><@]+)/,"\\1\n\\2\\3" - # Delete prompt - cfg.gsub! /^\r*([-\w. ]+\.[-\w. ]+\.[-\w. ]+[#>]\s+)$/, '' - cfg + # handle paging + expect /-Press Any Key For More-+.*$/ do |data, re| + send " " + data.sub re, '' + end - end - - cfg :ssh do - pre_logout "exit" - end - + cmd 'version' do |cfg| + comment cfg + end + + cmd 'showconfig' do |cfg| + # Delete hour and date which change each run + # cfg.gsub! /\sCurrent Time: \S+\s\S+\s+\S+\s\S+\s\S+/, ' Current Time:' + # Delete select passphrase display option + cfg.gsub! /Do you want to mask the password\? Files with masked passwords cannot be loaded/, '' + cfg.gsub! /^\s+y/, '' + # Delete space + cfg.gsub! /\n\s{25}/, '' + # Delete after line + cfg.gsub! /([\/\-,.\w><@]+)(\s{27})/, "\\1" + # Add a carriage return + cfg.gsub! /([\/\-,.\w><@]+)(\s{6,8})([\/\-,.\w><@]+)/, "\\1\n\\2\\3" + # Delete prompt + cfg.gsub! /^\r*([-\w. ]+\.[-\w. ]+\.[-\w. ]+[#>]\s+)$/, '' + cfg + end + + cfg :ssh do + pre_logout "exit" + end end diff --git a/lib/oxidized/model/ciscosmb.rb b/lib/oxidized/model/ciscosmb.rb index deb4768..ef6f4e6 100644 --- a/lib/oxidized/model/ciscosmb.rb +++ b/lib/oxidized/model/ciscosmb.rb @@ -1,5 +1,4 @@ class CiscoSMB < Oxidized::Model - # Cisco Small Business 300, 500, and ESW2 series switches # http://www.cisco.com/c/en/us/support/switches/small-business-300-series-managed-switches/products-release-notes-list.html @@ -24,11 +23,11 @@ class CiscoSMB < Oxidized::Model cmd 'show version' do |cfg| comment cfg end - + cmd 'show system' do |cfg| comment cfg end - + cmd 'show bootvar' do |cfg| comment cfg end @@ -49,8 +48,7 @@ class CiscoSMB < Oxidized::Model post_login 'terminal datadump' # Disable pager post_login 'terminal width 0' post_login 'terminal len 0' - pre_logout 'exit' #exit returns to previous priv level, no way to quit from exec(#) + pre_logout 'exit' # exit returns to previous priv level, no way to quit from exec(#) pre_logout 'exit' end - end diff --git a/lib/oxidized/model/comnetms.rb b/lib/oxidized/model/comnetms.rb new file mode 100644 index 0000000..1ce4601 --- /dev/null +++ b/lib/oxidized/model/comnetms.rb @@ -0,0 +1,43 @@ +class ComnetMS < Oxidized::Model + # Comnet Microsemi Switch + prompt /^\r?([\w.@()-]+[#>]\s?)$/ + comment '! ' + + cmd :all do |cfg| + cfg.each_line.to_a[1..-2].join + end + + cmd 'show running-config' do |cfg| + cfg.gsub! "\n\r", "\n" + cfg.gsub! /^[\r\n\s]*Building configuration\.\.\.\n/, '' + cfg.gsub! /^end\n/, '' + cfg + end + + cmd 'show version' do |cfg| + cfg.gsub! "\n\r", "\n" + cfg.gsub! /^MEMORY\s*:.*\n/, '' + cfg.gsub! /^FLASH\s*:.*\n/, '' + cfg.gsub! /^Previous Restart\s*:.*\n/, '' + cfg.gsub! /^System Time\s*:.*\n/, '' + cfg.gsub! /^System Uptime\s*:.*\n/, '' + comment cfg + end + + cfg :telnet do + username /^Username:/i + password /^Password:/i + end + + cfg :telnet, :ssh do + if vars :enable + post_login do + send "enable\n" + cmd vars(:enable) + end + end + post_login 'terminal length 0' + post_login 'terminal width 0' + pre_logout 'exit' + end +end diff --git a/lib/oxidized/model/comware.rb b/lib/oxidized/model/comware.rb index a5b7190..f20cd4d 100644 --- a/lib/oxidized/model/comware.rb +++ b/lib/oxidized/model/comware.rb @@ -1,23 +1,23 @@ class Comware < Oxidized::Model # HP (A-series)/H3C/3Com Comware - + # sometimes the prompt might have a leading nul or trailing ASCII Bell (^G) prompt /^\0*(<[\w.-]+>).?$/ comment '# ' # example how to handle pager - #expect /^\s*---- More ----$/ do |data, re| + # expect /^\s*---- More ----$/ do |data, re| # send ' ' # data.sub re, '' - #end + # end cmd :all do |cfg| - #cfg.gsub! /^.*\e\[42D/, '' # example how to handle pager - #skip rogue ^M + # cfg.gsub! /^.*\e\[42D/, '' # example how to handle pager + # skip rogue ^M cfg = cfg.gsub /\r/, '' cfg.each_line.to_a[1..-2].join end - + cmd :secret do |cfg| cfg.gsub! /^( snmp-agent community).*/, '\\1 <configuration removed>' cfg.gsub! /^( password hash).*/, '\\1 <configuration removed>' @@ -47,7 +47,7 @@ class Comware < Oxidized::Model end cmd 'display version' do |cfg| - cfg = cfg.each_line.select {|l| not l.match /uptime/i }.join + cfg = cfg.each_line.reject { |l| l.match /uptime/i }.join comment cfg end diff --git a/lib/oxidized/model/coriant8600.rb b/lib/oxidized/model/coriant8600.rb index a48ffa5..2e8bb76 100644 --- a/lib/oxidized/model/coriant8600.rb +++ b/lib/oxidized/model/coriant8600.rb @@ -1,7 +1,6 @@ class Coriant8600 < Oxidized::Model - comment '# ' - + prompt /^[^\s#>]+[#>]$/ cmd 'show hw-inventory' do |cfg| @@ -11,7 +10,7 @@ class Coriant8600 < Oxidized::Model cmd 'show flash' do |cfg| comment cfg end - + cmd 'show run' do |cfg| cfg end @@ -20,11 +19,10 @@ class Coriant8600 < Oxidized::Model username /^user name:$/ password /^password:$/ end - + cfg :telnet, :ssh do pre_logout 'exit' post_login 'enable' post_login 'terminal more off' end - end diff --git a/lib/oxidized/model/coriantgroove.rb b/lib/oxidized/model/coriantgroove.rb index 4fc44b7..9d81e82 100644 --- a/lib/oxidized/model/coriantgroove.rb +++ b/lib/oxidized/model/coriantgroove.rb @@ -1,11 +1,10 @@ class CoriantGroove < Oxidized::Model - comment '# ' - + prompt /^(\w+@.*>\s*)$/ cmd :all do |cfg| - cfg.each_line.to_a[1..-3].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" + cfg.each_line.to_a[1..-3].map { |line| line.delete("\r").rstrip }.join("\n") + "\n" end cmd 'show inventory' do |cfg| @@ -17,7 +16,7 @@ class CoriantGroove < Oxidized::Model cfg = cfg.each_line.to_a[0..-2].join comment cfg end - + cmd 'show config | display commands' do |cfg| cfg.each_line.to_a[1..-1].join end @@ -26,5 +25,4 @@ class CoriantGroove < Oxidized::Model post_login 'set -f cli-config cli-columns 65535' pre_logout 'quit -f' end - end diff --git a/lib/oxidized/model/corianttmos.rb b/lib/oxidized/model/corianttmos.rb index 76603f6..bc9618e 100644 --- a/lib/oxidized/model/corianttmos.rb +++ b/lib/oxidized/model/corianttmos.rb @@ -1,7 +1,6 @@ class CoriantTmos < Oxidized::Model - comment '# ' - + prompt /^[^\s#]+#\s$/ cmd 'show node extensive' do |cfg| @@ -21,5 +20,4 @@ class CoriantTmos < Oxidized::Model pre_logout 'exit' post_login 'enable config terminal length 0' end - end diff --git a/lib/oxidized/model/cumulus.rb b/lib/oxidized/model/cumulus.rb index 20acb8a..334e1e4 100644 --- a/lib/oxidized/model/cumulus.rb +++ b/lib/oxidized/model/cumulus.rb @@ -1,85 +1,81 @@ class Cumulus < Oxidized::Model - prompt /^((\w*)@(.*)):/ - comment '# ' - - - #add a comment in the final conf + comment '# ' + + # add a comment in the final conf def add_comment comment - "\n###### #{comment} ######\n" + "\n###### #{comment} ######\n" end cmd :all do |cfg| cfg.each_line.to_a[1..-2].join end - - #show the persistent configuration + + # show the persistent configuration pre do cfg = add_comment 'THE HOSTNAME' cfg += cmd 'cat /etc/hostname' - + cfg += add_comment 'THE HOSTS' cfg += cmd 'cat /etc/hosts' - + cfg += add_comment 'THE INTERFACES' cfg += cmd 'grep -r "" /etc/network/interface* | cut -d "/" -f 4-' - + cfg += add_comment 'RESOLV.CONF' cfg += cmd 'cat /etc/resolv.conf' - + cfg += add_comment 'NTP.CONF' cfg += cmd 'cat /etc/ntp.conf' - + cfg += add_comment 'IP Routes' cfg += cmd 'netstat -rn' - + cfg += add_comment 'SNMP settings' cfg += cmd 'cat /etc/snmp/snmpd.conf' - + cfg += add_comment 'QUAGGA DAEMONS' cfg += cmd 'cat /etc/quagga/daemons' - + cfg += add_comment 'QUAGGA ZEBRA' cfg += cmd 'cat /etc/quagga/zebra.conf' - + cfg += add_comment 'QUAGGA BGP' cfg += cmd 'cat /etc/quagga/bgpd.conf' - + cfg += add_comment 'QUAGGA OSPF' cfg += cmd 'cat /etc/quagga/ospfd.conf' - + cfg += add_comment 'QUAGGA OSPF6' cfg += cmd 'cat /etc/quagga/ospf6d.conf' - + cfg += add_comment 'QUAGGA CONF' cfg += cmd 'cat /etc/quagga/Quagga.conf' - + cfg += add_comment 'MOTD' cfg += cmd 'cat /etc/motd' - + cfg += add_comment 'PASSWD' cfg += cmd 'cat /etc/passwd' - + cfg += add_comment 'SWITCHD' cfg += cmd 'cat /etc/cumulus/switchd.conf' - + cfg += add_comment 'PORTS' cfg += cmd 'cat /etc/cumulus/ports.conf' - + cfg += add_comment 'TRAFFIC' cfg += cmd 'cat /etc/cumulus/datapath/traffic.conf' - + cfg += add_comment 'ACL' cfg += cmd 'iptables -L -n' - + cfg += add_comment 'VERSION' cfg += cmd 'cat /etc/cumulus/etc.replace/os-release' - + cfg += add_comment 'License' cfg += cmd 'cl-license' - end - cfg :telnet do username /^Username:/ @@ -89,6 +85,4 @@ class Cumulus < Oxidized::Model cfg :telnet, :ssh do pre_logout 'exit' end - - end diff --git a/lib/oxidized/model/datacom.rb b/lib/oxidized/model/datacom.rb index 5dbc080..5d5d220 100644 --- a/lib/oxidized/model/datacom.rb +++ b/lib/oxidized/model/datacom.rb @@ -1,5 +1,4 @@ class DataCom < Oxidized::Model - comment '! ' expect /^--More--\s+$/ do |data, re| @@ -34,5 +33,4 @@ class DataCom < Oxidized::Model password /^Password:\s$/ pre_logout 'exit' end - end diff --git a/lib/oxidized/model/dcnos.rb b/lib/oxidized/model/dcnos.rb new file mode 100644 index 0000000..59e6744 --- /dev/null +++ b/lib/oxidized/model/dcnos.rb @@ -0,0 +1,46 @@ +# DCNOS is a ZebOS derivative by DCN (http://www.dcnglobal.com/) +# In addition to products by DCN (now Yunke China), this OS type +# powers a number of re-branded OEM devices. + +# Developed against SNR S2950-24G 7.0.3.5 + +class DCNOS < Oxidized::Model + comment '! ' + + cmd :all do |cfg| + cfg.each_line.to_a[1..-1].join + end + + cmd 'show version' do |cfg| + cfg.gsub! /\s(Uptime is).*/, '' + comment cfg + end + + cmd 'show boot-files' do |cfg| + comment cfg + end + + cmd 'show flash' do |cfg| + comment cfg + end + + cmd 'show running-config' do |cfg| + cfg + end + + cfg :telnet do + username /^login:/i + password /^password:/i + end + + cfg :telnet, :ssh do + if vars :enable + post_login do + send "enable\n" + cmd vars(:enable) + end + end + post_login 'terminal length 0' + pre_logout 'exit' + end +end diff --git a/lib/oxidized/model/dlink.rb b/lib/oxidized/model/dlink.rb index 0d08793..6c604fb 100644 --- a/lib/oxidized/model/dlink.rb +++ b/lib/oxidized/model/dlink.rb @@ -11,7 +11,7 @@ class Dlink < Oxidized::Model end cmd :all do |cfg| - cfg.each_line.to_a[2..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" + cfg.each_line.to_a[2..-2].map { |line| line.delete("\r").rstrip }.join("\n") + "\n" end cmd 'show switch' do |cfg| diff --git a/lib/oxidized/model/dnos.rb b/lib/oxidized/model/dnos.rb index 5c3cd53..d8b1d96 100644 --- a/lib/oxidized/model/dnos.rb +++ b/lib/oxidized/model/dnos.rb @@ -1,15 +1,15 @@ -class DNOS < Oxidized::Model - +class DNOS < Oxidized::Model # Force10 DNOS model # comment '! ' cmd :all do |cfg| cfg.gsub! /^% Invalid input detected at '\^' marker\.$|^\s+\^$/, '' + cfg.gsub! /^Dell Networking OS uptime is\s.+/, '' # Omit constantly changing uptime info cfg.each_line.to_a[2..-2].join end - cmd :secret do |cfg| + cmd :secret do |cfg| cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' cfg.gsub! /secret (\d+) (\S+).*/, '<secret hidden>' cfg @@ -27,10 +27,6 @@ class DNOS < Oxidized::Model comment cfg end - cmd 'show system' do |cfg| - comment cfg - end - cmd 'show running-config' do |cfg| cfg = cfg.each_line.to_a[3..-1].join cfg @@ -51,7 +47,6 @@ class DNOS < Oxidized::Model post_login 'terminal length 0' post_login 'terminal width 0' pre_logout 'exit' - pre_logout 'exit' + pre_logout 'exit' end - end diff --git a/lib/oxidized/model/edgecos.rb b/lib/oxidized/model/edgecos.rb index bc205f5..3668769 100644 --- a/lib/oxidized/model/edgecos.rb +++ b/lib/oxidized/model/edgecos.rb @@ -1,6 +1,5 @@ class EdgeCOS < Oxidized::Model - - comment '! ' + comment '! ' cmd :secret do |cfg| cfg.gsub!(/password \d+ (\S+).*/, '<secret removed>') @@ -9,7 +8,7 @@ class EdgeCOS < Oxidized::Model end cmd :all do |cfg| - cfg.each_line.to_a[2..-2].join + cfg.each_line.to_a[2..-2].join end cmd 'show running-config' @@ -43,5 +42,4 @@ class EdgeCOS < Oxidized::Model post_login 'terminal length 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/edgeos.rb b/lib/oxidized/model/edgeos.rb index aa7a197..a723904 100644 --- a/lib/oxidized/model/edgeos.rb +++ b/lib/oxidized/model/edgeos.rb @@ -1,5 +1,4 @@ class Edgeos < Oxidized::Model - # EdgeOS # prompt /\@.*?\:~\$\s/ @@ -27,5 +26,4 @@ class Edgeos < Oxidized::Model cfg :telnet, :ssh do pre_logout 'exit' end - end diff --git a/lib/oxidized/model/edgeswitch.rb b/lib/oxidized/model/edgeswitch.rb index 7f5b1ea..36c0f9f 100644 --- a/lib/oxidized/model/edgeswitch.rb +++ b/lib/oxidized/model/edgeswitch.rb @@ -1,6 +1,5 @@ class EdgeSwitch < Oxidized::Model - -# Ubiquiti EdgeSwitch # + # Ubiquiti EdgeSwitch # comment '!' @@ -28,5 +27,4 @@ class EdgeSwitch < Oxidized::Model pre_logout 'quit' pre_logout 'n' end - end diff --git a/lib/oxidized/model/enterasys.rb b/lib/oxidized/model/enterasys.rb index 708d380..40f676d 100644 --- a/lib/oxidized/model/enterasys.rb +++ b/lib/oxidized/model/enterasys.rb @@ -1,5 +1,4 @@ class Enterasys < Oxidized::Model - # Enterasys B3/C3 models # prompt /^.+\w\(su\)->\s?$/ @@ -7,7 +6,7 @@ class Enterasys < Oxidized::Model comment '!' cmd :all do |cfg| - cfg.each_line.to_a[2..-3].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" + cfg.each_line.to_a[2..-3].map { |line| line.delete("\r").rstrip }.join("\n") + "\n" end cmd 'show system hardware' do |cfg| @@ -26,5 +25,4 @@ class Enterasys < Oxidized::Model cfg :ssh do pre_logout 'exit' end - end diff --git a/lib/oxidized/model/eos.rb b/lib/oxidized/model/eos.rb index a9f3ff3..f29910c 100644 --- a/lib/oxidized/model/eos.rb +++ b/lib/oxidized/model/eos.rb @@ -1,5 +1,4 @@ class EOS < Oxidized::Model - # Arista EOS model # prompt /^.+[#>]\s?$/ @@ -7,15 +6,15 @@ class EOS < Oxidized::Model comment '! ' cmd :all do |cfg| - cfg.each_line.to_a[1..-2].join + cfg.each_line.to_a[1..-2].join end cmd :secret do |cfg| - cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' - cfg.gsub! /username (\S+) privilege (\d+) (\S+).*/, '<secret hidden>' - cfg.gsub! /^(enable secret).*/, '\\1 <configuration removed>' - cfg.gsub! /^(tacacs-server key \d+).*/, '\\1 <configuration removed>' - cfg + cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' + cfg.gsub! /username (\S+) privilege (\d+) (\S+).*/, '<secret hidden>' + cfg.gsub! /^(enable secret).*/, '\\1 <configuration removed>' + cfg.gsub! /^(tacacs-server key \d+).*/, '\\1 <configuration removed>' + cfg end cmd 'show inventory | no-more' do |cfg| @@ -41,5 +40,4 @@ class EOS < Oxidized::Model end pre_logout 'exit' end - end diff --git a/lib/oxidized/model/fabricos.rb b/lib/oxidized/model/fabricos.rb index e6d921e..b150c51 100644 --- a/lib/oxidized/model/fabricos.rb +++ b/lib/oxidized/model/fabricos.rb @@ -1,22 +1,20 @@ class FabricOS < Oxidized::Model - # Brocade Fabric OS model # ## FIXME: Only ssh exec mode support, no telnet, no ssh screenscraping prompt /^([\w]+:+[\w]+[>]\s)$/ - comment '# ' + comment '# ' cmd 'chassisShow' do |cfg| comment cfg.each_line.reject { |line| line.match /Time Awake:/ or line.match /Power Usage \(Watts\):/ or line.match /Time Alive:/ or line.match /Update:/ }.join end cmd 'configShow -all' do |cfg| - cfg = cfg.each_line.reject { |line| line.match /date = /}.join + cfg = cfg.each_line.reject { |line| line.match /date = / }.join cfg end cfg :ssh do - exec true # don't run shell, run each command in exec channel + exec true # don't run shell, run each command in exec channel end - end diff --git a/lib/oxidized/model/firewareos.rb b/lib/oxidized/model/firewareos.rb index 1b3d07c..bd0008d 100644 --- a/lib/oxidized/model/firewareos.rb +++ b/lib/oxidized/model/firewareos.rb @@ -1,5 +1,4 @@ class FirewareOS < Oxidized::Model - prompt /^\[?\w*\]?\w*?(<\w*>)?(#|>)\s*$/ comment '-- ' @@ -15,7 +14,7 @@ class FirewareOS < Oxidized::Model cmd 'show sysinfo' do |cfg| # avoid commits due to uptime - cfg = cfg.each_line.select { |line| not line.match /(.*time.*)|(.*memory.*)|(.*cpu.*)/ } + cfg = cfg.each_line.reject { |line| line.match /(.*time.*)|(.*memory.*)|(.*cpu.*)/ } cfg = cfg.join comment cfg end @@ -25,6 +24,4 @@ class FirewareOS < Oxidized::Model cfg :ssh do pre_logout 'exit' end - end - diff --git a/lib/oxidized/model/ftos.rb b/lib/oxidized/model/ftos.rb index 1c3b8b4..3ef4de6 100644 --- a/lib/oxidized/model/ftos.rb +++ b/lib/oxidized/model/ftos.rb @@ -1,5 +1,4 @@ -class FTOS < Oxidized::Model - +class FTOS < Oxidized::Model # Force10 FTOS model # comment '! ' @@ -8,7 +7,7 @@ class FTOS < Oxidized::Model cfg.each_line.to_a[2..-2].join end - cmd :secret do |cfg| + cmd :secret do |cfg| cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' cfg.gsub! /secret (\d+) (\S+).*/, '<secret hidden>' cfg @@ -45,5 +44,4 @@ class FTOS < Oxidized::Model end pre_logout 'exit' end - end diff --git a/lib/oxidized/model/fujitsupy.rb b/lib/oxidized/model/fujitsupy.rb index 20a78dd..a2db909 100644 --- a/lib/oxidized/model/fujitsupy.rb +++ b/lib/oxidized/model/fujitsupy.rb @@ -1,5 +1,4 @@ class FujitsuPY < Oxidized::Model - prompt /^(\([\w.-]*\)\s#|^\S+\#\s)$/ comment '! ' @@ -7,13 +6,13 @@ class FujitsuPY < Oxidized::Model cfg.each_line.to_a[1..-2].join end -# 1Gbe switch + # 1Gbe switch cmd 'show version' do |cfg| cfg.gsub! /^(<ERROR> : 2 : format error)$/, '' comment cfg end -# 10Gbe switch + # 10Gbe switch cmd 'show system information' do |cfg| cfg.gsub! /^Current-time : [\w\s:]*$/, '' cfg.gsub! /^(\s{33}\^)$/, '' @@ -38,5 +37,4 @@ class FujitsuPY < Oxidized::Model send "n\n" end end - end diff --git a/lib/oxidized/model/gaiaos.rb b/lib/oxidized/model/gaiaos.rb index 434e774..8f13bcb 100644 --- a/lib/oxidized/model/gaiaos.rb +++ b/lib/oxidized/model/gaiaos.rb @@ -1,25 +1,23 @@ class GaiaOS < Oxidized::Model - # CheckPoint - Gaia OS Model - + # Gaia Prompt prompt /^([\[\]\w.@:-]+[#>]\s?)$/ # Comment tag comment '# ' - cmd :all do |cfg| cfg = cfg.each_line.to_a[1..-2].join end cmd :secret do |cfg| cfg.gsub! /^(set expert-password-hash ).*/, '\1<EXPERT PASSWORD REMOVED>' - cfg.gsub! /^(set user \S+ password-hash ).*/,'\1<USER PASSWORD REMOVED>' - cfg.gsub! /^(set ospf .* secret ).*/,'\1<OSPF KEY REMOVED>' - cfg.gsub! /^(set snmp community )(.*)( read-only.*)/,'\1<SNMP COMMUNITY REMOVED>\3' - cfg.gsub! /^(add snmp .* community )(.*)(\S?.*)/,'\1<SNMP COMMUNITY REMOVED>\3' - cfg.gsub! /(auth|privacy)(-pass-phrase-hashed )(\S*)/,'\1-pass-phrase-hashed <SNMP PASS-PHRASE REMOVED>' + cfg.gsub! /^(set user \S+ password-hash ).*/, '\1<USER PASSWORD REMOVED>' + cfg.gsub! /^(set ospf .* secret ).*/, '\1<OSPF KEY REMOVED>' + cfg.gsub! /^(set snmp community )(.*)( read-only.*)/, '\1<SNMP COMMUNITY REMOVED>\3' + cfg.gsub! /^(add snmp .* community )(.*)(\S?.*)/, '\1<SNMP COMMUNITY REMOVED>\3' + cfg.gsub! /(auth|privacy)(-pass-phrase-hashed )(\S*)/, '\1-pass-phrase-hashed <SNMP PASS-PHRASE REMOVED>' cfg end @@ -36,11 +34,9 @@ class GaiaOS < Oxidized::Model cfg end - cfg :ssh do # User shell must be /etc/cli.sh post_login 'set clienv rows 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/gcombnps.rb b/lib/oxidized/model/gcombnps.rb index 4a97162..e92c7ba 100644 --- a/lib/oxidized/model/gcombnps.rb +++ b/lib/oxidized/model/gcombnps.rb @@ -6,18 +6,18 @@ class GcomBNPS < Oxidized::Model # - S5330 (aka Fiberstore S3800) prompt /^\r?([\w.@()-]+?(\(1-16 chars\))?[#>:]\s?)$/ # also match SSH password promt (post_login commands are sent after the first prompt) - comment '! ' + comment '! ' -# alternative to handle the SSH login, but this breaks telnet -# expect /^Password\(1-16 chars\):/ do |data| -# send @node.auth[:password] + "\n" -# '' -# end + # alternative to handle the SSH login, but this breaks telnet + # expect /^Password\(1-16 chars\):/ do |data| + # send @node.auth[:password] + "\n" + # '' + # end # handle pager (can't be disabled?) expect /^\.\.\.\.press ENTER to next line, CTRL_C to quit, other key to next page\.\.\.\.$/ do |data, re| - send ' ' - data.sub re, '' + send ' ' + data.sub re, '' end cmd :all do |cfg| @@ -48,7 +48,6 @@ class GcomBNPS < Oxidized::Model comment out.join end - cmd 'show version' do |cfg| comment cfg end @@ -80,6 +79,4 @@ class GcomBNPS < Oxidized::Model cfg :telnet, :ssh do pre_logout 'exit' end - end - diff --git a/lib/oxidized/model/hatteras.rb b/lib/oxidized/model/hatteras.rb index 4192cbc..7341cc4 100644 --- a/lib/oxidized/model/hatteras.rb +++ b/lib/oxidized/model/hatteras.rb @@ -9,7 +9,6 @@ class Hatteras < Oxidized::Model data.sub re, '' end - cmd :secret do |cfg| cfg.gsub! /^(community) \S+/, '\\1 "<configuration removed>"' cfg.gsub! /^(communityString) "\S+"/, '\\1 "<configuration removed>"' @@ -22,14 +21,18 @@ class Hatteras < Oxidized::Model end cmd "show switch\r" do |cfg| - cfg = cfg.each_line.reject { |line| line.match /Switch uptime|Switch temperature|Last reset reason/ or - line.match /TermCpuUtil|^\s+\^$|ERROR: Bad command/ }.join + cfg = cfg.each_line.reject { |line| + line.match /Switch uptime|Switch temperature|Last reset reason/ or + line.match /TermCpuUtil|^\s+\^$|ERROR: Bad command/ + } .join comment cfg end cmd "show card\r" do |cfg| - cfg = cfg.each_line.reject { |line| line.match /Card uptime|Card temperature|Last reset reason/ or - line.match /TermCpuUtil|^\s+\^$|ERROR: Bad command/ }.join + cfg = cfg.each_line.reject { |line| + line.match /Card uptime|Card temperature|Last reset reason/ or + line.match /TermCpuUtil|^\s+\^$|ERROR: Bad command/ + } .join comment cfg end diff --git a/lib/oxidized/model/hirschmann.rb b/lib/oxidized/model/hirschmann.rb index 82432d7..858b198 100644 --- a/lib/oxidized/model/hirschmann.rb +++ b/lib/oxidized/model/hirschmann.rb @@ -1,10 +1,9 @@ class Hirschmann < Oxidized::Model + prompt /^[\(\w\s\w\)]+\s[>|#]+?$/ - prompt /^[\(\w\s\w\)]+\s[>|#]+?$/ - comment '## ' - - #Handle pager + + # Handle pager expect /^--More--.*$/ do |data, re| send 'a' data.sub re, '' @@ -22,11 +21,11 @@ class Hirschmann < Oxidized::Model cfg.gsub! /^Average CPU Utilization.*\n/, "" comment cfg end - + cmd 'show running-config' do |cfg| - cfg.gsub! /^users.*\n/, "" + cfg.gsub! /^users.*\n/, "" cfg - end + end cfg :telnet do username /^User:/ @@ -34,8 +33,7 @@ class Hirschmann < Oxidized::Model end cfg :telnet, :ssh do - post_login 'enable' - pre_logout 'logout' + post_login 'enable' + pre_logout 'logout' end - end diff --git a/lib/oxidized/model/hpebladesystem.rb b/lib/oxidized/model/hpebladesystem.rb index 27673de..75d2dbf 100644 --- a/lib/oxidized/model/hpebladesystem.rb +++ b/lib/oxidized/model/hpebladesystem.rb @@ -4,13 +4,13 @@ class HPEBladeSystem < Oxidized::Model prompt /.*> / comment '# ' - #expect /^\s*--More--\s+.*$/ do |data, re| + # expect /^\s*--More--\s+.*$/ do |data, re| # send ' ' # data.sub re, '' - #end + # end cmd :all do |cfg| - cfg = cfg.delete("\r").each_line.to_a[0..-1].map{|line|line.rstrip}.join("\n") + "\n" + cfg = cfg.delete("\r").each_line.to_a[0..-1].map { |line| line.rstrip }.join("\n") + "\n" cfg.each_line.to_a[0..-2].join end @@ -22,7 +22,7 @@ class HPEBladeSystem < Oxidized::Model cmd 'show oa info' do |cfg| comment cfg end - + cmd 'show oa network' do |cfg| comment cfg end @@ -30,15 +30,15 @@ class HPEBladeSystem < Oxidized::Model cmd 'show oa certificate' do |cfg| comment cfg end - + cmd 'show sshfingerprint' do |cfg| comment cfg end - + cmd 'show fru' do |cfg| comment cfg end - + cmd 'show network' do |cfg| cfg.gsub! /Last Update:.*$/i, '' comment cfg @@ -55,15 +55,15 @@ class HPEBladeSystem < Oxidized::Model cmd 'show server list' do |cfg| comment cfg end - + cmd 'show server names' do |cfg| comment cfg end - + cmd 'show server port map all' do |cfg| comment cfg end - + cmd 'show server info all' do |cfg| comment cfg end @@ -72,14 +72,14 @@ class HPEBladeSystem < Oxidized::Model cfg.gsub! /^#(Generated on:) .*$/, '\\1 <removed>' cfg.gsub /^\s+/, '' end - + cfg :telnet do username /\slogin:/ password /^Password: / end - - cfg :telnet, :ssh do - post_login "set script mode on" - pre_logout "exit" - end + + cfg :telnet, :ssh do + post_login "set script mode on" + pre_logout "exit" + end end diff --git a/lib/oxidized/model/hpemsa.rb b/lib/oxidized/model/hpemsa.rb index 4fe636f..68485a1 100644 --- a/lib/oxidized/model/hpemsa.rb +++ b/lib/oxidized/model/hpemsa.rb @@ -1,5 +1,4 @@ class HpeMsa < Oxidized::Model - prompt /^#\s?$/ cmd 'show configuration' @@ -8,6 +7,4 @@ class HpeMsa < Oxidized::Model post_login 'set cli-parameters pager disabled' pre_logout 'exit' end - end - diff --git a/lib/oxidized/model/ios.rb b/lib/oxidized/model/ios.rb index 4e7d223..8069f83 100644 --- a/lib/oxidized/model/ios.rb +++ b/lib/oxidized/model/ios.rb @@ -1,24 +1,23 @@ class IOS < Oxidized::Model - prompt /^([\w.@()-]+[#>]\s?)$/ comment '! ' # example how to handle pager - #expect /^\s--More--\s+.*$/ do |data, re| + # expect /^\s--More--\s+.*$/ do |data, re| # send ' ' # data.sub re, '' - #end + # end # non-preferred way to handle additional PW prompt - #expect /^[\w.]+>$/ do |data| + # expect /^[\w.]+>$/ do |data| # send "enable\n" # send vars(:enable) + "\n" # data - #end + # end cmd :all do |cfg| - #cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager - #cfg.gsub! /\cH+/, '' # example how to handle pager + # cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager + # cfg.gsub! /\cH+/, '' # example how to handle pager # get rid of errors for commands that don't work on some devices cfg.gsub! /^% Invalid input detected at '\^' marker\.$|^\s+\^$/, '' cfg.each_line.to_a[1..-2].join @@ -43,64 +42,64 @@ class IOS < Oxidized::Model comments = [] comments << cfg.lines.first lines = cfg.lines - lines.each_with_index do |line,i| - slave = '' - slaveslot = '' + lines.each_with_index do |line, i| + slave = '' + slaveslot = '' - if line.match /^Slave in slot (\d+) is running/ - slave = " Slave:"; - slaveslot = ", slot #{$1}"; - end + if line.match /^Slave in slot (\d+) is running/ + slave = " Slave:"; + slaveslot = ", slot #{$1}"; + end - if line.match /^Compiled (.*)$/ - comments << "Image:#{slave} Compiled: #{$1}" - end + if line.match /^Compiled (.*)$/ + comments << "Image:#{slave} Compiled: #{$1}" + end - if line.match /^(?:Cisco )?IOS .* Software,? \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ - comments << "Image:#{slave} Software: #{$1}, #{$2}" - end + if line.match /^(?:Cisco )?IOS .* Software,? \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ + comments << "Image:#{slave} Software: #{$1}, #{$2}" + end - if line.match /^ROM: (IOS \S+ )?(System )?Bootstrap.*(Version.*)$/ - comments << "ROM Bootstrap: #{$3}" - end + if line.match /^ROM: (IOS \S+ )?(System )?Bootstrap.*(Version.*)$/ + comments << "ROM Bootstrap: #{$3}" + end - if line.match /^BOOTFLASH: .*(Version.*)$/ - comments << "BOOTFLASH: #{$1}" - end + if line.match /^BOOTFLASH: .*(Version.*)$/ + comments << "BOOTFLASH: #{$1}" + end - if line.match /^(\d+[kK]) bytes of (non-volatile|NVRAM)/ - comments << "Memory: nvram #{$1}" - end + if line.match /^(\d+[kK]) bytes of (non-volatile|NVRAM)/ + comments << "Memory: nvram #{$1}" + end - if line.match /^(\d+[kK]) bytes of (flash memory|flash internal|processor board System flash|ATA CompactFlash)/i - comments << "Memory: flash #{$1}" - end + if line.match /^(\d+[kK]) bytes of (flash memory|flash internal|processor board System flash|ATA CompactFlash)/i + comments << "Memory: flash #{$1}" + end - if line.match (/^(\d+[kK]) bytes of (Flash|ATA)?.*PCMCIA .*(slot|disk) ?(\d)/i) - comments << "Memory: pcmcia #{$2} #{$3}#{$4} #{$1}"; - end + if line.match (/^(\d+[kK]) bytes of (Flash|ATA)?.*PCMCIA .*(slot|disk) ?(\d)/i) + comments << "Memory: pcmcia #{$2} #{$3}#{$4} #{$1}"; + end - if line.match /(\S+(?:\sseries)?)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i - sproc = $1 - cpu = $2 - mem = $3 - cpuxtra = '' - comments << "Chassis type:#{slave} #{sproc}"; - comments << "Memory:#{slave} main #{mem}"; - # check the next two lines for more CPU info - if cfg.lines[i+1].match /processor board id (\S+)/i - comments << "Processor ID: #{$1}"; - end - if cfg.lines[i+2].match /(cpu at |processor: |#{cpu} processor,)/i - # change implementation to impl and prepend comma - cpuxtra = cfg.lines[i+2].gsub(/implementation/,'impl').gsub(/^/,', ').chomp; - end - comments << "CPU:#{slave} #{cpu}#{cpuxtra}#{slaveslot}"; + if line.match /(\S+(?:\sseries)?)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i + sproc = $1 + cpu = $2 + mem = $3 + cpuxtra = '' + comments << "Chassis type:#{slave} #{sproc}"; + comments << "Memory:#{slave} main #{mem}"; + # check the next two lines for more CPU info + if cfg.lines[i + 1].match /processor board id (\S+)/i + comments << "Processor ID: #{$1}"; end - - if line.match /^System image file is "([^\"]*)"$/ - comments << "Image: #{$1}" + if cfg.lines[i + 2].match /(cpu at |processor: |#{cpu} processor,)/i + # change implementation to impl and prepend comma + cpuxtra = cfg.lines[i + 2].gsub(/implementation/, 'impl').gsub(/^/, ', ').chomp; end + comments << "CPU:#{slave} #{cpu}#{cpuxtra}#{slaveslot}"; + end + + if line.match /^System image file is "([^\"]*)"$/ + comments << "Image: #{$1}" + end end comments << "\n" comment comments.join "\n" @@ -143,5 +142,4 @@ class IOS < Oxidized::Model post_login 'terminal width 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/iosxe.rb b/lib/oxidized/model/iosxe.rb new file mode 100644 index 0000000..1945e11 --- /dev/null +++ b/lib/oxidized/model/iosxe.rb @@ -0,0 +1,5 @@ +# IOS parser should work here + +require_relative 'ios.rb' + +IOSXE = IOS diff --git a/lib/oxidized/model/iosxr.rb b/lib/oxidized/model/iosxr.rb index ac2f798..1635e57 100644 --- a/lib/oxidized/model/iosxr.rb +++ b/lib/oxidized/model/iosxr.rb @@ -1,5 +1,4 @@ class IOSXR < Oxidized::Model - # IOS XR model # prompt /^(\r?[\w.@:\/-]+[#>]\s?)$/ @@ -9,7 +8,7 @@ class IOSXR < Oxidized::Model cfg.each_line.to_a[2..-2].join end - cmd :secret do |cfg| + cmd :secret do |cfg| cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' cfg.gsub! /secret (\d+) (\S+).*/, '<secret hidden>' cfg @@ -45,5 +44,4 @@ class IOSXR < Oxidized::Model end pre_logout 'exit' end - end diff --git a/lib/oxidized/model/ipos.rb b/lib/oxidized/model/ipos.rb index 938f12d..753c6b1 100644 --- a/lib/oxidized/model/ipos.rb +++ b/lib/oxidized/model/ipos.rb @@ -1,5 +1,4 @@ class IPOS < Oxidized::Model - # Ericsson SSR (IPOS) # Redback SE (SEOS) @@ -54,7 +53,7 @@ class IPOS < Oxidized::Model post_login 'terminal length 0' if vars :enable post_login do - cmd "enable" + cmd "enable" cmd vars(:enable) end end @@ -63,5 +62,4 @@ class IPOS < Oxidized::Model send "n\n" end end - end diff --git a/lib/oxidized/model/ironware.rb b/lib/oxidized/model/ironware.rb index 386d585..32dbf47 100644 --- a/lib/oxidized/model/ironware.rb +++ b/lib/oxidized/model/ironware.rb @@ -1,19 +1,17 @@ class IronWare < Oxidized::Model - prompt /^.*(telnet|ssh)\@.+[>#]\s?$/i comment '! ' - #to handle pager without enable - #expect /^((.*)--More--(.*))$/ do |data, re| + # to handle pager without enable + # expect /^((.*)--More--(.*))$/ do |data, re| # send ' ' # data.sub re, '' - #end - + # end - #to remove backspace (if handle pager without enable) - #expect /^((.*)[\b](.*))$/ do |data, re| + # to remove backspace (if handle pager without enable) + # expect /^((.*)[\b](.*))$/ do |data, re| # data.sub re, '' - #end + # end cmd :all do |cfg| # sometimes ironware inserts arbitrary whitespace after commands are @@ -22,17 +20,17 @@ class IronWare < Oxidized::Model end cmd 'show version' do |cfg| - cfg.gsub! /(^((.*)[Ss]ystem uptime(.*))$)/, '' #remove unwanted line system uptime + cfg.gsub! /(^((.*)[Ss]ystem uptime(.*))$)/, '' # remove unwanted line system uptime cfg.gsub! /(^((.*)[Tt]he system started at(.*))$)/, '' - cfg.gsub! /[Uu]p\s?[Tt]ime is .*/,'' + cfg.gsub! /[Uu]p\s?[Tt]ime is .*/, '' comment cfg end cmd 'show chassis' do |cfg| - cfg.encode!("UTF-8", :invalid => :replace, :undef => :replace) #sometimes ironware returns broken encoding - cfg.gsub! /(^((.*)Current temp(.*))$)/, '' #remove unwanted lines current temperature - cfg.gsub! /Speed = [A-Z-]{2,6} \(\d{2,3}\%\)/, '' #remove unwanted lines Speed Fans + cfg.encode!("UTF-8", :invalid => :replace, :undef => :replace) # sometimes ironware returns broken encoding + cfg.gsub! /(^((.*)Current temp(.*))$)/, '' # remove unwanted lines current temperature + cfg.gsub! /Speed = [A-Z-]{2,6} \(\d{2,3}\%\)/, '' # remove unwanted lines Speed Fans cfg.gsub! /current speed is [A-Z]{2,6} \(\d{2,3}\%\)/, '' cfg.gsub! /Fan \d* - STATUS: OK \D*\d*./, '' # Fix for ADX Fan speed reporting cfg.gsub! /\d* deg C/, '' # Fix for ADX temperature reporting @@ -73,7 +71,7 @@ class IronWare < Oxidized::Model password /^(Please Enter Password ?|Password):/ end - #handle pager with enable + # handle pager with enable cfg :telnet, :ssh do if vars :enable post_login do @@ -86,5 +84,4 @@ class IronWare < Oxidized::Model post_login 'terminal length 0' pre_logout "logout\nexit\nexit\n" end - end diff --git a/lib/oxidized/model/isam.rb b/lib/oxidized/model/isam.rb index 1709500..8b8b5d5 100644 --- a/lib/oxidized/model/isam.rb +++ b/lib/oxidized/model/isam.rb @@ -1,6 +1,6 @@ class ISAM < Oxidized::Model - #Alcatel ISAM 7302/7330 FTTN - + # Alcatel ISAM 7302/7330 FTTN + prompt /^([\w.:@-]+>#\s)$/ comment '# ' @@ -8,7 +8,7 @@ class ISAM < Oxidized::Model cfg.each_line.to_a[1..-2].join end - cfg :telnet do + cfg :telnet do username /^login:\s*/ password /^password:\s*/ end @@ -19,7 +19,7 @@ class ISAM < Oxidized::Model post_login 'environment inhibit-alarms print no-more' pre_logout 'logout' end - + cmd 'show software-mngt oswp detail' do |cfg| comment cfg end @@ -31,5 +31,4 @@ class ISAM < Oxidized::Model cmd 'info configure flat' do |cfg| cfg end - end diff --git a/lib/oxidized/model/junos.rb b/lib/oxidized/model/junos.rb index 2ea0179..737a000 100644 --- a/lib/oxidized/model/junos.rb +++ b/lib/oxidized/model/junos.rb @@ -1,6 +1,5 @@ class JunOS < Oxidized::Model - - comment '# ' + comment '# ' def telnet @input.class.to_s.match(/Telnet/) @@ -8,7 +7,7 @@ class JunOS < Oxidized::Model cmd :all do |cfg| cfg = cfg.lines.to_a[1..-2].join if screenscrape - cfg.gsub!(/ scale-subscriber (\s+)(\d+)/,' scale-subscriber <count>') + cfg.gsub!(/ scale-subscriber (\s+)(\d+)/, ' scale-subscriber <count>') cfg.lines.map { |line| line.rstrip }.join("\n") + "\n" end @@ -32,7 +31,7 @@ class JunOS < Oxidized::Model out = '' case @model when 'mx960' - out << cmd('show chassis fabric reachability') { |cfg| comment cfg } + out << cmd('show chassis fabric reachability') { |cfg| comment cfg } when /^(ex22|ex33|ex4|ex8|qfx)/ out << cmd('show virtual-chassis') { |cfg| comment cfg } end @@ -49,7 +48,7 @@ class JunOS < Oxidized::Model end cfg :ssh do - exec true # don't run shell, run each command in exec channel + exec true # don't run shell, run each command in exec channel end cfg :telnet, :ssh do @@ -57,5 +56,4 @@ class JunOS < Oxidized::Model post_login 'set cli screen-width 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/masteros.rb b/lib/oxidized/model/masteros.rb index 587fdc4..c03beb1 100644 --- a/lib/oxidized/model/masteros.rb +++ b/lib/oxidized/model/masteros.rb @@ -1,8 +1,7 @@ class MasterOS < Oxidized::Model - # MRV MasterOS model # -comment '!' + comment '!' cmd :secret do |cfg| cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' @@ -43,5 +42,4 @@ comment '!' end pre_logout 'exit' end - end diff --git a/lib/oxidized/model/mlnxos.rb b/lib/oxidized/model/mlnxos.rb index 49f3369..990417d 100644 --- a/lib/oxidized/model/mlnxos.rb +++ b/lib/oxidized/model/mlnxos.rb @@ -1,8 +1,7 @@ class MLNXOS < Oxidized::Model - prompt /([\w.@()-\[:\s\]]+[#>]\s)$/ - comment '## ' - + comment '## ' + # Pager Handling expect /.+lines\s\d+\-\d+([\s]|\/\d+\s\(END\)\s).+$/ do |data, re| send ' ' @@ -11,7 +10,7 @@ class MLNXOS < Oxidized::Model cmd :all do |cfg| cfg.gsub! /\[\?1h=\r/, '' # Pager Handling - cfg.gsub! /\r\[K/,'' # Pager Handling + cfg.gsub! /\r\[K/, '' # Pager Handling cfg.gsub! /\s/, '' # Linebreak Handling cfg.gsub! /^CPU\ load\ averages\:\s.+/, '' # Omit constantly changing CPU info cfg.gsub! /^System\ memory\:\s.+/, '' # Omit constantly changing memory info diff --git a/lib/oxidized/model/model.rb b/lib/oxidized/model/model.rb index a2a71cb..438357f 100644 --- a/lib/oxidized/model/model.rb +++ b/lib/oxidized/model/model.rb @@ -7,29 +7,34 @@ module Oxidized 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 '@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='# ' + + def comment _comment = '# ' return @comment if @comment @comment = block_given? ? yield : _comment end - def prompt _prompt=nil + + def prompt _prompt = nil @prompt or @prompt = _prompt end + def cfg *methods, &block [methods].flatten.each do |method| @cfg[method.to_s] << block end end + def cfgs @cfg end - def cmd _cmd=nil, &block + + def cmd _cmd = nil, &block if _cmd.class == Symbol @cmd[_cmd] << block else @@ -37,12 +42,15 @@ module Oxidized end Oxidized.logger.debug "lib/oxidized/model/model.rb Added #{_cmd} to the commands list" end + def cmds @cmd end + def expect re, &block @expect << [re, block] end + def expects @expect end @@ -83,6 +91,7 @@ module Oxidized 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 @@ -166,6 +175,5 @@ module Oxidized output.set_cmd(name) output end - end end diff --git a/lib/oxidized/model/mtrlrfs.rb b/lib/oxidized/model/mtrlrfs.rb index 8baa4e9..31b4f22 100644 --- a/lib/oxidized/model/mtrlrfs.rb +++ b/lib/oxidized/model/mtrlrfs.rb @@ -1,5 +1,4 @@ class Mtrlrfs < Oxidized::Model - # Motorola RFS/Extreme WM comment '# ' @@ -7,7 +6,7 @@ class Mtrlrfs < Oxidized::Model cmd :all do |cfg| # xos inserts leading \r characters and other trailing white space. # this deletes extraneous \r and trailing white space. - cfg.each_line.to_a[1..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" + cfg.each_line.to_a[1..-2].map { |line| line.delete("\r").rstrip }.join("\n") + "\n" end cmd 'show version' do |cfg| @@ -32,6 +31,4 @@ class Mtrlrfs < Oxidized::Model send "n\n" end end - end - diff --git a/lib/oxidized/model/ndms.rb b/lib/oxidized/model/ndms.rb new file mode 100644 index 0000000..1947f91 --- /dev/null +++ b/lib/oxidized/model/ndms.rb @@ -0,0 +1,24 @@ +class NDMS < Oxidized::Model + # Pull config from Zyxel Keenetic devices from version NDMS >= 2.0 + + comment '! ' + + prompt /^([\w.@()-]+[#>]\s?)/m + + cmd 'show version' do |cfg| + cfg = cfg.each_line.to_a[1..-3].join + comment cfg + end + + cmd 'show running-config' do |cfg| + cfg = cfg.each_line.to_a[1..-2] + cfg = cfg.reject { |line| line.match /(clock date|checksum)/ }.join + cfg + end + + cfg :telnet do + username /^Login:/ + password /^Password:/ + pre_logout 'exit' + end +end diff --git a/lib/oxidized/model/netgear.rb b/lib/oxidized/model/netgear.rb index 0ab1349..40b0924 100644 --- a/lib/oxidized/model/netgear.rb +++ b/lib/oxidized/model/netgear.rb @@ -1,15 +1,15 @@ class Netgear < Oxidized::Model - comment '!' - prompt /^(\([\w\-.]+\)\s[#>])$/ + prompt /^(\([\w\s\-.]+\)\s[#>])$/ cmd :secret do |cfg| cfg.gsub!(/password (\S+)/, 'password <hidden>') + cfg.gsub!(/encrypted (\S+)/, 'encrypted <hidden>') cfg end cfg :telnet do - username /^User:/ + username /^(User:|Applying Interface configuration, please wait ...)/ end cfg :telnet, :ssh do @@ -36,5 +36,4 @@ class Netgear < Oxidized::Model cmd 'show running-config' do |cfg| cfg.gsub! /^(!.*Time).*$/, '\1' end - end diff --git a/lib/oxidized/model/netscaler.rb b/lib/oxidized/model/netscaler.rb index 9ca66b6..00d1b71 100644 --- a/lib/oxidized/model/netscaler.rb +++ b/lib/oxidized/model/netscaler.rb @@ -1,5 +1,4 @@ class NetScaler < Oxidized::Model - prompt /^\>\s*$/ comment '# ' @@ -20,5 +19,4 @@ class NetScaler < Oxidized::Model cfg :ssh do pre_logout 'exit' end - end diff --git a/lib/oxidized/model/nos.rb b/lib/oxidized/model/nos.rb index ec7c818..4049aa5 100644 --- a/lib/oxidized/model/nos.rb +++ b/lib/oxidized/model/nos.rb @@ -1,5 +1,4 @@ class NOS < Oxidized::Model - # Brocade Network Operating System prompt /^(?:\e\[..h)?[\w.-]+# $/ @@ -38,8 +37,7 @@ class NOS < Oxidized::Model cfg :telnet, :ssh do post_login 'terminal length 0' - #post_login 'terminal width 0' + # post_login 'terminal width 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/nxos.rb b/lib/oxidized/model/nxos.rb index 60d6037..ec1f807 100644 --- a/lib/oxidized/model/nxos.rb +++ b/lib/oxidized/model/nxos.rb @@ -1,8 +1,12 @@ class NXOS < Oxidized::Model - prompt /^(\r?[\w.@_()-]+[#]\s?)$/ comment '! ' + def filter cfg + cfg.gsub! /\r\n?/, "\n" + cfg.gsub! prompt, '' + end + cmd :secret do |cfg| cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' cfg.gsub! /^(snmp-server user (\S+) (\S+) auth (\S+)) (\S+) (priv) (\S+)/, '\\1 <configuration removed> ' @@ -10,18 +14,23 @@ class NXOS < Oxidized::Model cfg.gsub! /^(radius-server key).*/, '\\1 <secret hidden>' cfg end - + cmd 'show version' do |cfg| + cfg = filter cfg cfg = cfg.each_line.take_while { |line| not line.match(/uptime/i) } comment cfg.join "" end cmd 'show inventory' do |cfg| + cfg = filter cfg comment cfg - end + end cmd 'show running-config' do |cfg| + cfg = filter cfg + cfg.gsub! /^(show run.*)$/, '! \1' cfg.gsub! /^!Time:[^\n]*\n/, '' + cfg.gsub! /^[\w.@_()-]+[#].*$/, '' cfg end diff --git a/lib/oxidized/model/oneos.rb b/lib/oxidized/model/oneos.rb index eeaa2ce..35332c8 100644 --- a/lib/oxidized/model/oneos.rb +++ b/lib/oxidized/model/oneos.rb @@ -1,24 +1,23 @@ class OneOS < Oxidized::Model - prompt /^([\w.@()-]+#\s?)$/ comment '! ' # example how to handle pager - #expect /^\s--More--\s+.*$/ do |data, re| + # expect /^\s--More--\s+.*$/ do |data, re| # send ' ' # data.sub re, '' - #end + # end # non-preferred way to handle additional PW prompt - #expect /^[\w.]+>$/ do |data| + # expect /^[\w.]+>$/ do |data| # send "enable\n" # send vars(:enable) + "\n" # data - #end + # end cmd :all do |cfg| - #cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager - #cfg.gsub! /\cH+/, '' # example how to handle pager + # cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager + # cfg.gsub! /\cH+/, '' # example how to handle pager cfg.each_line.to_a[1..-2].join end @@ -54,5 +53,4 @@ class OneOS < Oxidized::Model post_login 'term len 0' pre_logout 'exit' end - end diff --git a/lib/oxidized/model/opengear.rb b/lib/oxidized/model/opengear.rb index b7c697f..1f94edb 100644 --- a/lib/oxidized/model/opengear.rb +++ b/lib/oxidized/model/opengear.rb @@ -1,8 +1,7 @@ class OpenGear < Oxidized::Model + comment '# ' - comment '# ' - - prompt /^(\$\s)?$/ + prompt /^(\$\s)$/ cmd :secret do |cfg| cfg.gsub!(/password (\S+)/, 'password <secret removed>') @@ -15,7 +14,6 @@ class OpenGear < Oxidized::Model cmd 'config -g config' cfg :ssh do - exec true # don't run shell, run each command in exec channel + exec true # don't run shell, run each command in exec channel end - end diff --git a/lib/oxidized/model/openwrt.rb b/lib/oxidized/model/openwrt.rb new file mode 100644 index 0000000..7ba9e98 --- /dev/null +++ b/lib/oxidized/model/openwrt.rb @@ -0,0 +1,77 @@ +class OpenWrt < Oxidized::Model + prompt /^[^#]+#/ + comment '#' + + cmd 'cat /etc/banner' do |cfg| + comment "#### Info: /etc/banner #####\n#{cfg}" + end + + cmd 'cat /proc/cpuinfo' do |cfg| + comment "#### Info: /proc/cpuinfo #####\n#{cfg}" + end + + cmd 'cat /etc/openwrt_release' do |cfg| + comment "#### Info: /etc/openwrt_release #####\n#{cfg}" + end + + cmd 'sysupgrade -l' do |cfg| + @sysupgradefiles = cfg + comment "#### Info: sysupgrade -l #####\n#{cfg}" + end + + cmd 'cat /proc/mtd' do |cfg| + @mtdpartitions = cfg + comment "#### Info: /proc/mtd #####\n#{cfg}" + end + + post do + cfg = [] + binary_files = vars(:openwrt_binary_files) || %w[/etc/dropbear/dropbear_rsa_host_key] + non_sensitive_files = vars(:openwrt_non_sensitive_files) || %w[rpcd uhttpd] + partitions_to_backup = vars(:openwrt_partitions_to_backup) || %w[art devinfo u_env config caldata] + @sysupgradefiles.lines.each do |sysupgradefile| + sysupgradefile = sysupgradefile.strip + if sysupgradefile.start_with?('/etc/config/') + unless sysupgradefile.end_with?('-opkg') + filename = sysupgradefile.split('/')[-1] + cfg << comment("#### File: #{sysupgradefile} #####") + uciexport = cmd("uci export #{filename}") + Oxidized.logger.debug "Exporting uci config - #{filename}" + if vars(:remove_secret) && !(non_sensitive_files.include? filename) + Oxidized.logger.debug "Scrubbing uci config - #{filename}" + uciexport.gsub!(/^(\s+option\s+(password|key)\s+')[^']+'/, '\\1<secret hidden>\'') + end + cfg << uciexport + end + elsif binary_files.include? sysupgradefile + Oxidized.logger.debug "Exporting binary file - #{sysupgradefile}" + cfg << comment("#### Binary file: #{sysupgradefile} #####") + cfg << comment("Decode using 'echo -en <data> | gzip -dc > #{sysupgradefile}'") + cfg << cmd("gzip -c #{sysupgradefile} | hexdump -ve '1/1 \"_x%.2x\"' | tr _ \\") + elsif vars(:remove_secret) && sysupgradefile == '/etc/shadow' + Oxidized.logger.debug 'Exporting and scrubbing /etc/shadow' + cfg << comment("#### File: #{sysupgradefile} #####") + shadow = cmd("cat #{sysupgradefile}") + shadow.gsub!(/^([^:]+:)[^:]*(:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:)/, '\\1\\2') + cfg << shadow + else + Oxidized.logger.debug "Exporting file - #{sysupgradefile}" + cfg << comment("#### File: #{sysupgradefile} #####") + cfg << cmd("cat #{sysupgradefile}") + end + end + @mtdpartitions.scan(/(\w+):\s+\w+\s+\w+\s+"(.*)"/).each do |partition, name| + next unless vars(:openwrt_backup_partitions) && partitions_to_backup.include?(name) + Oxidized.logger.debug "Exporting partition - #{name}(#{partition})" + cfg << comment("#### Partition: #{name} /dev/#{partition} #####") + cfg << comment("Decode using 'echo -en <data> | gzip -dc > #{name}'") + cfg << cmd("dd if=/dev/#{partition} 2>/dev/null | gzip -c | hexdump -ve '1/1 \"%.2x\"'") + end + cfg.join "\n" + end + + cfg :ssh do + exec true + pre_logout 'exit' + end +end diff --git a/lib/oxidized/model/opnsense.rb b/lib/oxidized/model/opnsense.rb index b874fca..a8f7a47 100644 --- a/lib/oxidized/model/opnsense.rb +++ b/lib/oxidized/model/opnsense.rb @@ -1,21 +1,19 @@ class OpnSense < Oxidized::Model - # minimum required permissions: "System: Shell account access" # must enable SSH and password-based SSH access - + cmd :all do |cfg| cfg.each_line.to_a[1..-1].join end - + cmd 'cat /conf/config.xml' do |cfg| cfg.gsub! /\s<revision>\s*<time>\d*<\/time>\s*.*\s*.*\s*<\/revision>/, '' cfg.gsub! /\s<last_rule_upd_time>\d*<\/last_rule_upd_time>/, '' cfg end - + cfg :ssh do exec true pre_logout 'exit' end - end diff --git a/lib/oxidized/model/outputs.rb b/lib/oxidized/model/outputs.rb index a668e9d..23a37f5 100644 --- a/lib/oxidized/model/outputs.rb +++ b/lib/oxidized/model/outputs.rb @@ -1,7 +1,6 @@ module Oxidized class Model class Outputs - def to_cfg type_to_str(nil) end @@ -23,7 +22,7 @@ module Oxidized end def type type - @outputs.select { |out| out.type==type } + @outputs.select { |out| out.type == type } end def types @@ -35,7 +34,6 @@ module Oxidized def initialize @outputs = [] end - end end end diff --git a/lib/oxidized/model/panos.rb b/lib/oxidized/model/panos.rb index 67ccaec..422a9fe 100644 --- a/lib/oxidized/model/panos.rb +++ b/lib/oxidized/model/panos.rb @@ -1,8 +1,7 @@ class PanOS < Oxidized::Model - # PaloAlto PAN-OS model # - comment '! ' + comment '! ' prompt /^[\w.\@:\(\)-]+>\s?$/ diff --git a/lib/oxidized/model/pfsense.rb b/lib/oxidized/model/pfsense.rb index 5849160..13a6370 100644 --- a/lib/oxidized/model/pfsense.rb +++ b/lib/oxidized/model/pfsense.rb @@ -1,20 +1,24 @@ class PfSense < Oxidized::Model - # use other use than 'admin' user, 'admin' user cannot get ssh/exec. See issue #535 - + cmd :all do |cfg| cfg.each_line.to_a[1..-1].join end - + + cmd :secret do |cfg| + cfg.gsub! /(\s+<bcrypt-hash>)[^<]+(<\/bcrypt-hash>)/, '\\1<secret hidden>\\2' + cfg.gsub! /(\s+<password>)[^<]+(<\/password>)/, '\\1<secret hidden>\\2' + cfg + end + cmd 'cat /cf/conf/config.xml' do |cfg| cfg.gsub! /\s<revision>\s*<time>\d*<\/time>\s*.*\s*.*\s*<\/revision>/, '' cfg.gsub! /\s<last_rule_upd_time>\d*<\/last_rule_upd_time>/, '' cfg end - + cfg :ssh do exec true pre_logout 'exit' end - end diff --git a/lib/oxidized/model/planet.rb b/lib/oxidized/model/planet.rb index 9ce9cf9..56e688c 100644 --- a/lib/oxidized/model/planet.rb +++ b/lib/oxidized/model/planet.rb @@ -1,24 +1,23 @@ class Planet < Oxidized::Model - prompt /^\r?([\w.@()-]+[#>]\s?)$/ comment '! ' # example how to handle pager - #expect /^\s--More--\s+.*$/ do |data, re| + # expect /^\s--More--\s+.*$/ do |data, re| # send ' ' # data.sub re, '' - #end + # end # non-preferred way to handle additional PW prompt - #expect /^[\w.]+>$/ do |data| + # expect /^[\w.]+>$/ do |data| # send "enable\n" # send vars(:enable) + "\n" # data - #end + # end cmd :all do |cfg| - #cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager - #cfg.gsub! /\cH+/, '' # example how to handle pager + # cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager + # cfg.gsub! /\cH+/, '' # example how to handle pager cfg.each_line.to_a[1..-2].join end @@ -39,7 +38,7 @@ class Planet < Oxidized::Model cfg = cfg.each_line.to_a[0...-2] - # Strip system (up)time and temperature + # Strip system (up)time and temperature cfg = cfg.reject { |line| line.match /System Time\s*:.*/ } cfg = cfg.reject { |line| line.match /System Uptime\s*:.*/ } cfg = cfg.reject { |line| line.match /Temperature\s*:.*/ } @@ -47,13 +46,12 @@ class Planet < Oxidized::Model comment cfg.join end - cmd 'show running-config' do |cfg| cfg.gsub! "\n\r", "\n" cfg = cfg.each_line.to_a cfg = cfg.reject { |line| line.match "Building configuration..." } - + if @planetsgs cfg << cmd('show transceiver detail | include transceiver detail information|found|Type|length|Nominal|wavelength|Base information') do |cfg| comment cfg @@ -62,7 +60,6 @@ class Planet < Oxidized::Model cfg.join end - cfg :telnet do username /^Username:/ @@ -80,5 +77,4 @@ class Planet < Oxidized::Model end pre_logout 'exit' end - end diff --git a/lib/oxidized/model/powerconnect.rb b/lib/oxidized/model/powerconnect.rb index f602a36..bf36f65 100644 --- a/lib/oxidized/model/powerconnect.rb +++ b/lib/oxidized/model/powerconnect.rb @@ -1,12 +1,11 @@ class PowerConnect < Oxidized::Model - prompt /^([\w\s.@-]+[#>]\s?)$/ # allow spaces in hostname..dell does not limit it.. # - comment '! ' + comment '! ' expect /^\s*--More--\s+.*$/ do |data, re| - send ' ' - data.sub re, '' + send ' ' + data.sub re, '' end cmd :all do |cfg| @@ -22,7 +21,7 @@ class PowerConnect < Oxidized::Model if (@stackable.nil?) @stackable = true if cfg.match /(U|u)nit\s/ end - cfg = cfg.split("\n").select { |line| not line[/Up\sTime/] } + cfg = cfg.split("\n").reject { |line| line[/Up\sTime/] } comment cfg.join("\n") + "\n" end @@ -52,7 +51,6 @@ class PowerConnect < Oxidized::Model post_login "terminal length 0" pre_logout "logout" pre_logout "exit" - end def clean cfg @@ -72,9 +70,8 @@ class PowerConnect < Oxidized::Model end out << line.strip end - out = out.select { |line| not line[/Up\sTime/] } + out = out.reject { |line| line[/Up\sTime/] } out = comment out.join "\n" out << "\n" end - end diff --git a/lib/oxidized/model/procurve.rb b/lib/oxidized/model/procurve.rb index 444fb5b..f9175b1 100644 --- a/lib/oxidized/model/procurve.rb +++ b/lib/oxidized/model/procurve.rb @@ -1,10 +1,9 @@ class Procurve < Oxidized::Model - # some models start lines with \r # previous command is repeated followed by "\eE", which sometimes ends up on last line prompt /^\r?([\w.-]+# )$/ - comment '! ' + comment '! ' # replace next line control sequence with a new line expect /(\e\[1M\e\[\??\d+(;\d+)*[A-Za-z]\e\[1L)|(\eE)/ do |data, re| @@ -67,7 +66,7 @@ class Procurve < Oxidized::Model # not supported on all models cmd 'show system information' do |cfg| - cfg = cfg.each_line.select { |line| not line.match /(.*CPU.*)|(.*Up Time.*)|(.*Total.*)|(.*Free.*)|(.*Lowest.*)|(.*Missed.*)/ } + cfg = cfg.each_line.reject { |line| line.match /(.*CPU.*)|(.*Up Time.*)|(.*Total.*)|(.*Free.*)|(.*Lowest.*)|(.*Missed.*)/ } cfg = cfg.join comment cfg end @@ -80,6 +79,13 @@ class Procurve < Oxidized::Model end cfg :telnet, :ssh do + # preferred way to handle additional passwords + if vars :enable + post_login do + send "enable\n" + cmd vars(:enable) + end + end post_login 'no page' pre_logout "logout\ny\nn" end @@ -87,5 +93,4 @@ class Procurve < Oxidized::Model cfg :ssh do pty_options({ chars_wide: 1000 }) end - end diff --git a/lib/oxidized/model/quantaos.rb b/lib/oxidized/model/quantaos.rb index 5197aa8..8dbdf3b 100644 --- a/lib/oxidized/model/quantaos.rb +++ b/lib/oxidized/model/quantaos.rb @@ -1,13 +1,12 @@ class QuantaOS < Oxidized::Model - prompt /^\((\w|\S)+\) (>|#)$/ comment '! ' - + cmd 'show run' do |cfg| cfg.each_line.select do |line| not line.match /^!.*$/ and - not line.match /^\((\w|\S)+\) (>|#)$/ and - not line.match /^show run$/ + not line.match /^\((\w|\S)+\) (>|#)$/ and + not line.match /^show run$/ end.join end @@ -31,5 +30,4 @@ class QuantaOS < Oxidized::Model send "n\n" end end - end diff --git a/lib/oxidized/model/routeros.rb b/lib/oxidized/model/routeros.rb index 6717446..c729126 100644 --- a/lib/oxidized/model/routeros.rb +++ b/lib/oxidized/model/routeros.rb @@ -18,9 +18,9 @@ class RouterOS < Oxidized::Model run_cmd = vars(:remove_secret) ? '/export hide-sensitive' : '/export' cmd run_cmd do |cfg| cfg.gsub! /\x1B\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]/, '' # strip ANSI colours - cfg.gsub! /\\\r\n\s+/, '' # strip new line - cfg.gsub! /# inactive time\r\n/, '' # Remove time based system comment - cfg = cfg.split("\n").select { |line| not line[/^\#\s\w{3}\/\d{2}\/\d{4}.*$/] } + cfg.gsub! /\\\r\n\s+/, '' # strip new line + cfg.gsub! /# inactive time\r\n/, '' # Remove time based system comment + cfg = cfg.split("\n").reject { |line| line[/^\#\s\w{3}\/\d{2}\/\d{4}.*$/] } cfg.join("\n") + "\n" end end diff --git a/lib/oxidized/model/saos.rb b/lib/oxidized/model/saos.rb index 5a4e79e..97547b5 100644 --- a/lib/oxidized/model/saos.rb +++ b/lib/oxidized/model/saos.rb @@ -1,5 +1,4 @@ class SAOS < Oxidized::Model - # Ciena SAOS switch # used for 6.x devices diff --git a/lib/oxidized/model/screenos.rb b/lib/oxidized/model/screenos.rb index 0258898..9b52f9f 100644 --- a/lib/oxidized/model/screenos.rb +++ b/lib/oxidized/model/screenos.rb @@ -1,8 +1,7 @@ -class ScreenOS < Oxidized::Model - +class ScreenOS < Oxidized::Model # Netscreen ScreenOS model # - comment '! ' + comment '! ' prompt /^[\w.:\(\)-]+->\s?$/ @@ -10,7 +9,7 @@ class ScreenOS < Oxidized::Model cfg.each_line.to_a[2..-2].join end - cmd :secret do |cfg| + cmd :secret do |cfg| cfg.gsub! /^(set admin name) .*|^(set admin password) .*/, '\\1 <removed>' cfg.gsub! /^(set admin user .* password) .* (.*)/, '\\1 <removed> \\2' cfg.gsub! /(secret|password|preshare) .*/, '\\1 <secret hidden>' @@ -41,5 +40,4 @@ class ScreenOS < Oxidized::Model send "n" end end - end diff --git a/lib/oxidized/model/sgos.rb b/lib/oxidized/model/sgos.rb index 3d42a53..894e042 100644 --- a/lib/oxidized/model/sgos.rb +++ b/lib/oxidized/model/sgos.rb @@ -1,5 +1,4 @@ class SGOS < Oxidized::Model - comment '!- ' prompt /\w+>|#/ @@ -20,14 +19,14 @@ class SGOS < Oxidized::Model comment cfg end - cmd :secret do |cfg| + cmd :secret do |cfg| cfg.gsub! /^(security hashed-enable-password).*/, '\\1 <secret hidden>' cfg.gsub! /^(security hashed-password).*/, '\\1 <secret hidden>' cfg end cmd 'show configuration expanded noprompts with-keyrings unencrypted' do |cfg| - cfg.gsub! /^(!- Local time).*/,"" + cfg.gsub! /^(!- Local time).*/, "" cfg.gsub! /^(archive-configuration encrypted-password).*/, "" cfg.gsub! /^(download encrypted-password).*/, "" cfg diff --git a/lib/oxidized/model/siklu.rb b/lib/oxidized/model/siklu.rb index 2bdfbc3..2203bda 100644 --- a/lib/oxidized/model/siklu.rb +++ b/lib/oxidized/model/siklu.rb @@ -1,5 +1,4 @@ class Siklu < Oxidized::Model - # Siklu EtherHaul # prompt /^[\w-]+>$/ @@ -15,5 +14,4 @@ class Siklu < Oxidized::Model cfg :ssh do pre_logout 'exit' end - end diff --git a/lib/oxidized/model/slxos.rb b/lib/oxidized/model/slxos.rb index 934da5b..1afc8b1 100644 --- a/lib/oxidized/model/slxos.rb +++ b/lib/oxidized/model/slxos.rb @@ -1,35 +1,34 @@ class SLXOS < Oxidized::Model - prompt /^.*[>#]\s?$/i - comment '! ' + comment '! ' cmd 'show version' do |cfg| - cfg.gsub! /(^((.*)[Ss]ystem [Uu]ptime(.*))$)/, '' #remove unwanted line system uptime - cfg.gsub! /[Uu]p\s?[Tt]ime is .*/,'' + cfg.gsub! /(^((.*)[Ss]ystem [Uu]ptime(.*))$)/, '' # remove unwanted line system uptime + cfg.gsub! /[Uu]p\s?[Tt]ime is .*/, '' comment cfg end cmd 'show chassis' do |cfg| - cfg.encode!("UTF-8", :invalid => :replace, :undef => :replace) #sometimes ironware returns broken encoding - cfg.gsub! /.*Power Usage.*/, '' #remove unwanted lines power usage - cfg.gsub! /Time A(live|wake).*/, '' #remove unwanted lines time alive/awake + cfg.encode!("UTF-8", :invalid => :replace, :undef => :replace) # sometimes ironware returns broken encoding + cfg.gsub! /.*Power Usage.*/, '' # remove unwanted lines power usage + cfg.gsub! /Time A(live|wake).*/, '' # remove unwanted lines time alive/awake cfg.gsub! /([\[]*)1([\]]*)<->([\[]*)2([\]]*)(<->([\[]*)3([\]]*))*/, '' comment cfg end cmd 'show system' do |cfg| - cfg.gsub! /Up Time.*/, '' #removes uptime line - cfg.gsub! /Current Time.*/, '' #remove current time line - cfg.gsub! /.*speed is.*/, '' #removes fan speed lines + cfg.gsub! /Up Time.*/, '' # removes uptime line + cfg.gsub! /Current Time.*/, '' # remove current time line + cfg.gsub! /.*speed is.*/, '' # removes fan speed lines comment cfg end cmd 'show slots' do |cfg| cfg.gsub! /^-*^$/, '' # some slx devices are fixed config - cfg.gsub! /syntax error: element does not exist/, '' # same as above + cfg.gsub! /syntax error: element does not exist/, '' # same as above comment cfg end @@ -45,7 +44,7 @@ class SLXOS < Oxidized::Model password /^(Please Enter Password ?|Password):/ end - #handle pager with enable + # handle pager with enable cfg :telnet, :ssh do if vars :enable post_login do @@ -55,7 +54,6 @@ class SLXOS < Oxidized::Model end post_login '' post_login 'terminal length 0' - pre_logout 'exit' + pre_logout 'exit' end - end diff --git a/lib/oxidized/model/sros.rb b/lib/oxidized/model/sros.rb index 289bed3..d809147 100644 --- a/lib/oxidized/model/sros.rb +++ b/lib/oxidized/model/sros.rb @@ -1,5 +1,4 @@ class SROS < Oxidized::Model - # # Nokia SR OS (TiMOS) (formerly TiMetra, Alcatel, Alcatel-Lucent). # Used in 7705 SAR, 7210 SAS, 7450 ESS, 7750 SR, 7950 XRS, and NSP. diff --git a/lib/oxidized/model/stoneos.rb b/lib/oxidized/model/stoneos.rb new file mode 100644 index 0000000..d2bc017 --- /dev/null +++ b/lib/oxidized/model/stoneos.rb @@ -0,0 +1,32 @@ +class StoneOS < Oxidized::Model + # Hillstone Networks StoneOS software + + prompt /^\r?[\w.()-]+[#>](\s)?$/ + comment '# ' + + expect /^\s.*--More--.*$/ do |data, re| + send ' ' + data.sub re, '' + end + + cmd :all do |cfg| + cfg.each_line.to_a[1..-2].join + end + + cmd 'show configuration running' + + cmd 'show version' do |cfg| + comment cfg + end + + cfg :telnet do + username(/^login:/) + password(/^Password:/) + end + + cfg :telnet, :ssh do + post_login 'terminal length 256' + post_login 'terminal width 512' + pre_logout 'exit' + end +end diff --git a/lib/oxidized/model/tmos.rb b/lib/oxidized/model/tmos.rb index 390046d..69b0e1b 100644 --- a/lib/oxidized/model/tmos.rb +++ b/lib/oxidized/model/tmos.rb @@ -1,5 +1,4 @@ class TMOS < Oxidized::Model - comment '# ' cmd :secret do |cfg| @@ -46,7 +45,6 @@ class TMOS < Oxidized::Model cmd('cat /config/partitions/*/bigip.conf') { |cfg| comment cfg } cfg :ssh do - exec true # don't run shell, run each command in exec channel + exec true # don't run shell, run each command in exec channel end - end diff --git a/lib/oxidized/model/tplink.rb b/lib/oxidized/model/tplink.rb index bf13803..2a61fa5 100644 --- a/lib/oxidized/model/tplink.rb +++ b/lib/oxidized/model/tplink.rb @@ -1,26 +1,25 @@ class TPLink < Oxidized::Model - # tp-link prompt prompt /^\r?([\w.@()-]+[#>]\s?)$/ - comment '! ' + comment '! ' # handle paging # workaround for sometimes missing whitespaces with "\s?" expect /Press\s?any\s?key\s?to\s?continue\s?\(Q\s?to\s?quit\)/ do |data, re| - send ' ' - data.sub re, '' + send ' ' + data.sub re, '' end # send carriage return because \n with the command is not enough # checks if line ends with prompt >,# or \r,\nm otherwise send \r expect /[^>#\r\n]$/ do |data, re| - send "\r" - data.sub re, '' + send "\r" + data.sub re, '' end cmd :all do |cfg| # normalize linefeeds - cfg.gsub! /(\r|\r\n|\n\r)/,"\n" + cfg.gsub! /(\r|\r\n|\n\r)/, "\n" # remove empty lines cfg.each_line.reject { |line| line.match /^[\r\n\s\u0000#]+$/ }.join end @@ -31,7 +30,7 @@ class TPLink < Oxidized::Model cfg end - cmd 'show system-info' do |cfg| + cmd 'show system-info' do |cfg| comment cfg.each_line.to_a[3..-3].join end @@ -58,8 +57,5 @@ class TPLink < Oxidized::Model send "exit\r" send "logout\r" end - end - end - diff --git a/lib/oxidized/model/trango.rb b/lib/oxidized/model/trango.rb index b2aa1e7..b55b277 100644 --- a/lib/oxidized/model/trango.rb +++ b/lib/oxidized/model/trango.rb @@ -1,8 +1,8 @@ class Trango < Oxidized::Model # take a Trangolink sysinfo output and turn it into a configuration file - + prompt /^#>\s?/ - comment '# ' + comment '# ' cmd 'sysinfo' do |cfg| out = [] @@ -47,16 +47,15 @@ class Trango < Oxidized::Model end if line.match /\[IP\] (\S+) \[Subnet Mask\] (\S+) \[Gateway\] (\S+)/ out << "ipconfig " + Regexp.last_match[1] + ' ' + - Regexp.last_match[2] + ' ' + - Regexp.last_match[3] + Regexp.last_match[2] + ' ' + + Regexp.last_match[3] end - end + end comments.push(*out).join "\n" - end + end cfg :telnet do password /Password:/ pre_logout 'exit' end - end diff --git a/lib/oxidized/model/ucs.rb b/lib/oxidized/model/ucs.rb index a1f6c10..4418b68 100644 --- a/lib/oxidized/model/ucs.rb +++ b/lib/oxidized/model/ucs.rb @@ -1,5 +1,4 @@ class UCS < Oxidized::Model - prompt /^(\r?[\w.@_()-]+[#]\s?)$/ comment '! ' diff --git a/lib/oxidized/model/voltaire.rb b/lib/oxidized/model/voltaire.rb index 1e7fad2..62a62e5 100644 --- a/lib/oxidized/model/voltaire.rb +++ b/lib/oxidized/model/voltaire.rb @@ -1,18 +1,16 @@ class VOLTAIRE < Oxidized::Model - prompt /([\w.@()-\[:\s\]]+[#>]\s|(One or more tests have failed.*))$/ - comment '## ' - + comment '## ' + # Pager Handling expect /.+lines\s\d+\-\d+([\s]|\/\d+\s\(END\)\s).+$/ do |data, re| send ' ' data.sub re, '' end - cmd :all do |cfg| cfg.gsub! /\[\?1h=\r/, '' # Pager Handling - cfg.gsub! /\r\[K/,'' # Pager Handling + cfg.gsub! /\r\[K/, '' # Pager Handling cfg.gsub! /\s/, '' # Linebreak Handling cfg.gsub! /^CPU\ load\ averages\:\s.+/, '' # Omit constantly changing CPU info cfg.gsub! /^System\ memory\:\s.+/, '' # Omit constantly changing memory info @@ -27,7 +25,6 @@ class VOLTAIRE < Oxidized::Model cfg end - cmd 'version show' do |cfg| comment cfg end diff --git a/lib/oxidized/model/voss.rb b/lib/oxidized/model/voss.rb index 6b15fb3..32958ce 100644 --- a/lib/oxidized/model/voss.rb +++ b/lib/oxidized/model/voss.rb @@ -10,7 +10,7 @@ class Voss < Oxidized::Model # needed for proper formatting after post_login cmd('') { |cfg| comment "#{cfg}\n" } - + # Get sys-info and remove information that changes such has temperature and power cmd 'show sys-info' do |cfg| cfg.gsub! /(^((.*)SysUpTime(.*))$)/, 'removed SysUpTime' @@ -38,5 +38,4 @@ class Voss < Oxidized::Model post_login 'enable' post_login 'terminal more disable' end - end diff --git a/lib/oxidized/model/vrp.rb b/lib/oxidized/model/vrp.rb index 98229c3..42762c2 100644 --- a/lib/oxidized/model/vrp.rb +++ b/lib/oxidized/model/vrp.rb @@ -1,6 +1,6 @@ class VRP < Oxidized::Model # Huawei VRP - + prompt /^(<[\w.-]+>)$/ comment '# ' @@ -13,19 +13,19 @@ class VRP < Oxidized::Model cmd :all do |cfg| cfg.each_line.to_a[1..-2].join end - + cfg :telnet do username /^Username:$/ password /^Password:$/ end - cfg :telnet, :ssh do + cfg :telnet, :ssh do post_login 'screen-length 0 temporary' pre_logout 'quit' end cmd 'display version' do |cfg| - cfg = cfg.each_line.select {|l| not l.match /uptime/ }.join + cfg = cfg.each_line.reject { |l| l.match /uptime/ }.join comment cfg end @@ -36,5 +36,4 @@ class VRP < Oxidized::Model cmd 'display current-configuration all' do |cfg| cfg end - end diff --git a/lib/oxidized/model/vyatta.rb b/lib/oxidized/model/vyatta.rb index 57ec9d3..fb6b0d1 100644 --- a/lib/oxidized/model/vyatta.rb +++ b/lib/oxidized/model/vyatta.rb @@ -1,7 +1,6 @@ class Vyatta < Oxidized::Model - # Brocade Vyatta / VyOS model # - + prompt /\@.*?\:~\$\s/ cmd :all do |cfg| @@ -27,5 +26,4 @@ class Vyatta < Oxidized::Model cfg :telnet, :ssh do pre_logout 'exit' end - end diff --git a/lib/oxidized/model/weos.rb b/lib/oxidized/model/weos.rb index 1b20286..2856666 100644 --- a/lib/oxidized/model/weos.rb +++ b/lib/oxidized/model/weos.rb @@ -1,6 +1,5 @@ class WEOS < Oxidized::Model - - #Westell WEOS, works with Westell 8178G, Westell 8266G + # Westell WEOS, works with Westell 8178G, Westell 8266G prompt /^(\s[\w.@-]+[#>]\s?)$/ @@ -18,5 +17,4 @@ class WEOS < Oxidized::Model post_login 'cli more disable' pre_logout 'logout' end - end diff --git a/lib/oxidized/model/xos.rb b/lib/oxidized/model/xos.rb index 90f6f4a..5ce8017 100644 --- a/lib/oxidized/model/xos.rb +++ b/lib/oxidized/model/xos.rb @@ -1,5 +1,4 @@ class XOS < Oxidized::Model - # Extreme Networks XOS prompt /^*?[\w .-]+# $/ @@ -8,7 +7,7 @@ class XOS < Oxidized::Model cmd :all do |cfg| # xos inserts leading \r characters and other trailing white space. # this deletes extraneous \r and trailing white space. - cfg.each_line.to_a[1..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" + cfg.each_line.to_a[1..-2].map { |line| line.delete("\r").rstrip }.join("\n") + "\n" end cmd 'show version' do |cfg| @@ -23,11 +22,14 @@ class XOS < Oxidized::Model comment cfg end - cmd 'show switch'do |cfg| + cmd 'show switch' do |cfg| comment cfg.each_line.reject { |line| line.match /Time:/ or line.match /boot/i }.join end - cmd 'show configuration' + cmd 'show configuration' do |cfg| + cfg = cfg.each_line.reject { |line| line.match /^#(\s[\w]+\s)(Configuration generated)/ }.join + cfg + end cmd 'show policy detail' do |cfg| comment cfg @@ -45,5 +47,4 @@ class XOS < Oxidized::Model send "n\n" end end - end diff --git a/lib/oxidized/model/zhoneolt.rb b/lib/oxidized/model/zhoneolt.rb index b60edb2..ce6df29 100644 --- a/lib/oxidized/model/zhoneolt.rb +++ b/lib/oxidized/model/zhoneolt.rb @@ -18,7 +18,7 @@ class ZhoneOLT < Oxidized::Model end cmd :all do |cfg| - cfg.each_line.to_a[1..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" + cfg.each_line.to_a[1..-2].map { |line| line.delete("\r").rstrip }.join("\n") + "\n" end cmd 'swversion' do |cfg| @@ -39,7 +39,7 @@ class ZhoneOLT < Oxidized::Model end cmd 'dump console' do |cfg| - cfg = cfg.each_line.select { |line| not line.match /To Abort the operation enter Ctrl-C/ }.join + cfg = cfg.each_line.reject { |line| line.match /To Abort the operation enter Ctrl-C/ }.join end # zhone technically supports ssh, but it locks up a ton. Especially when diff --git a/lib/oxidized/model/zynos.rb b/lib/oxidized/model/zynos.rb index 89be8af..581d405 100644 --- a/lib/oxidized/model/zynos.rb +++ b/lib/oxidized/model/zynos.rb @@ -1,12 +1,10 @@ class ZyNOS < Oxidized::Model - # Used in Zyxel DSLAMs, such as SAM1316 - comment '! ' + comment '! ' cmd 'config-0' cfg :ftp do end - end diff --git a/lib/oxidized/model/zynoscli.rb b/lib/oxidized/model/zynoscli.rb new file mode 100644 index 0000000..ae64b04 --- /dev/null +++ b/lib/oxidized/model/zynoscli.rb @@ -0,0 +1,36 @@ +class ZyNOSCLI < Oxidized::Model + # Used in Zyxel DSLAMs, such as SAM1316 + + # Typical prompt "XGS4600#" + prompt /^([\w.@()-]+[#>]\s\e7)$/ + comment ';; ' + + cmd :all do |cfg| + cfg.gsub! /^.*\e7/, '' + end + cmd 'show stacking' + + cmd 'show version' + + cmd 'show running-config' + + cfg :telnet do + username /^User name:/i + password /^Password:/i + end + + cfg :telnet, :ssh do + if vars :enable + post_login do + send "enable\n" + # Interpret enable: true as meaning we won't be prompted for a password + unless vars(:enable).is_a? TrueClass + expect /[pP]assword:\s?$/ + send vars(:enable) + "\n" + end + expect /^.+[#]$/ + end + end + pre_logout 'exit' + end +end diff --git a/lib/oxidized/node.rb b/lib/oxidized/node.rb index 2b15d4e..4105da0 100644 --- a/lib/oxidized/node.rb +++ b/lib/oxidized/node.rb @@ -15,7 +15,8 @@ module Oxidized ip_addr, _ = opt[:ip].to_s.split("/") Oxidized.logger.debug 'IPADDR %s' % ip_addr.to_s @name = opt[:name] - @ip = IPAddr.new(ip_addr).to_s rescue nil + @ip = @name unless Oxidized.config.resolve_dns? + @ip ||= IPAddr.new(ip_addr).to_s rescue nil @ip ||= Resolv.new.getaddress @name @group = opt[:group] @input = resolve_input opt @@ -39,7 +40,7 @@ module Oxidized cfg_name = input.to_s.split('::').last.downcase next unless @model.cfg[cfg_name] and not @model.cfg[cfg_name].empty? @model.input = input = input.new - if config=run_input(input) + if config = run_input(input) Oxidized.logger.debug "lib/oxidized/node.rb: #{input.class.name} ran for #{name} successfully" status = :success break @@ -55,7 +56,7 @@ module Oxidized def run_input input rescue_fail = {} [input.class::RescueFail, input.class.superclass::RescueFail].each do |hash| - hash.each do |level,errors| + hash.each do |level, errors| errors.each do |err| rescue_fail[err] = level end @@ -64,9 +65,9 @@ module Oxidized begin input.connect(self) and input.get rescue *rescue_fail.keys => err - resc = '' + resc = '' if not level = rescue_fail[err.class] - resc = err.class.ancestors.find{|e|rescue_fail.keys.include? e} + resc = err.class.ancestors.find { |e| rescue_fail.keys.include? e } level = rescue_fail[resc] resc = " (rescued #{resc})" end @@ -196,20 +197,20 @@ module Oxidized end end - def resolve_key key, opt, global=nil + def resolve_key key, opt, global = nil # resolve key, first get global, then get group then get node config key_sym = key.to_sym key_str = key.to_s value = global Oxidized.logger.debug "node.rb: resolving node key '#{key}', with passed global value of '#{value}' and node value '#{opt[key_sym]}'" - #global + # global if not value and Oxidized.config.has_key?(key_str) value = Oxidized.config[key_str] Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from global" end - #group + # group if Oxidized.config.groups.has_key?(@group) if Oxidized.config.groups[@group].has_key?(key_str) value = Oxidized.config.groups[@group][key_str] @@ -217,7 +218,7 @@ module Oxidized end end - #model + # model # FIXME: warning: instance variable @model not initialized if Oxidized.config.models.has_key?(@model.class.name.to_s.downcase) if Oxidized.config.models[@model.class.name.to_s.downcase].has_key?(key_str) @@ -226,7 +227,7 @@ module Oxidized end end - #node + # node value = opt[key_sym] || value Oxidized.logger.debug "node.rb: returning node key '#{key}' with value '#{value}'" value @@ -239,6 +240,5 @@ module Oxidized def is_gitcrypt? opt (opt[:output] || Oxidized.config.output.default) == 'gitcrypt' end - end end diff --git a/lib/oxidized/node/stats.rb b/lib/oxidized/node/stats.rb index 6b5719c..17b9a13 100644 --- a/lib/oxidized/node/stats.rb +++ b/lib/oxidized/node/stats.rb @@ -14,11 +14,16 @@ module Oxidized @stats[job.status] ||= [] @stats[job.status].shift if @stats[job.status].size > MAX_STAT @stats[job.status].push stat + if job.status.equal? :success + @stats[:success_count] += 1 + else + @stats[:failure_count] += 1 + end end # @param [Symbol] status stats for specific status # @return [Hash,Array] Hash of stats for every status or Array of stats for specific status - def get status=nil + def get status = nil status ? @stats[status] : @stats end @@ -26,8 +31,9 @@ module Oxidized def initialize @stats = {} + @stats[:success_count] = 0 + @stats[:failure_count] = 0 end - end end end diff --git a/lib/oxidized/nodes.rb b/lib/oxidized/nodes.rb index 3f84e15..a159b48 100644 --- a/lib/oxidized/nodes.rb +++ b/lib/oxidized/nodes.rb @@ -6,13 +6,14 @@ module Oxidized class Nodes < Array attr_accessor :source, :jobs alias :put :unshift - def load node_want=nil + def load node_want = nil with_lock do new = [] @source = Oxidized.config.source.default Oxidized.mgr.add_source @source Oxidized.logger.info "lib/oxidized/nodes.rb: Loading nodes" - Oxidized.mgr.source[@source].new.load.each do |node| + nodes = Oxidized.mgr.source[@source].new.load node_want + nodes.each do |node| # we want to load specific node(s), not all of them next unless node_want? node_want, node begin @@ -42,7 +43,6 @@ module Oxidized end end - def list with_lock do map { |e| e.serialize } @@ -63,7 +63,7 @@ module Oxidized end # @param node [String] name of the node moved into the head of array - def next node, opt={} + def next node, opt = {} if waiting.find_node_index(node) with_lock do n = del node @@ -113,10 +113,10 @@ module Oxidized private - def initialize opts={} + def initialize opts = {} super() node = opts.delete :node - @mutex= Mutex.new # we compete for the nodes with webapi thread + @mutex = Mutex.new # we compete for the nodes with webapi thread if nodes = opts.delete(:nodes) replace nodes else @@ -129,7 +129,7 @@ module Oxidized end def find_index node - index { |e| e.name == node or e.ip == node} + index { |e| e.name == node or e.ip == node } end # @param node node which is removed from nodes list @@ -162,7 +162,7 @@ module Oxidized node.stats = old[i].stats node.last = old[i].last end - rescue Oxidized::NodeNotFound + rescue Oxidized::NodeNotFound end end sort_by! { |x| x.last.nil? ? Time.new(0) : x.last.end } diff --git a/lib/oxidized/output/file.rb b/lib/oxidized/output/file.rb index 45f72e1..bad1b6a 100644 --- a/lib/oxidized/output/file.rb +++ b/lib/oxidized/output/file.rb @@ -1,59 +1,58 @@ module Oxidized -class OxidizedFile < Output - require 'fileutils' + class OxidizedFile < Output + require 'fileutils' - attr_reader :commitref + attr_reader :commitref - def initialize - @cfg = Oxidized.config.output.file - end + def initialize + @cfg = Oxidized.config.output.file + end - def setup - if @cfg.empty? - Oxidized.asetus.user.output.file.directory = File.join(Config::Root, 'configs') - Oxidized.asetus.save :user - raise NoConfig, 'no output file config, edit ~/.config/oxidized/config' + def setup + if @cfg.empty? + Oxidized.asetus.user.output.file.directory = File.join(Config::Root, 'configs') + Oxidized.asetus.save :user + raise NoConfig, 'no output file config, edit ~/.config/oxidized/config' + end end - end - def store node, outputs, opt={} - file = File.expand_path @cfg.directory - if opt[:group] - file = File.join File.dirname(file), opt[:group] + def store node, outputs, opt = {} + file = File.expand_path @cfg.directory + if opt[:group] + file = File.join File.dirname(file), opt[:group] + end + FileUtils.mkdir_p file + file = File.join file, node + open(file, 'w') { |fh| fh.write outputs.to_cfg } + @commitref = file end - FileUtils.mkdir_p file - file = File.join file, node - open(file, 'w') { |fh| fh.write outputs.to_cfg } - @commitref = file - end - def fetch node, group - cfg_dir = File.expand_path @cfg.directory - node_name = node.name + def fetch node, group + cfg_dir = File.expand_path @cfg.directory + node_name = node.name - if group # group is explicitly defined by user - cfg_dir = File.join File.dirname(cfg_dir), group - File.read File.join(cfg_dir, node_name) - else - if File.exists? File.join(cfg_dir, node_name) # node configuration file is stored on base directory + if group # group is explicitly defined by user + cfg_dir = File.join File.dirname(cfg_dir), group File.read File.join(cfg_dir, node_name) else - path = Dir.glob(File.join(File.dirname(cfg_dir), '**', node_name)).first # fetch node in all groups - File.read path + if File.exists? File.join(cfg_dir, node_name) # node configuration file is stored on base directory + File.read File.join(cfg_dir, node_name) + else + path = Dir.glob(File.join(File.dirname(cfg_dir), '**', node_name)).first # fetch node in all groups + File.read path + end end + rescue Errno::ENOENT + return nil end - rescue Errno::ENOENT - return nil - end - def version node, group - # not supported - [] - end + def version node, group + # not supported + [] + end - def get_version node, group, oid - 'not supported' + def get_version node, group, oid + 'not supported' + end end - -end end diff --git a/lib/oxidized/output/git.rb b/lib/oxidized/output/git.rb index fee0ab6..8acfd46 100644 --- a/lib/oxidized/output/git.rb +++ b/lib/oxidized/output/git.rb @@ -1,74 +1,73 @@ module Oxidized -class Git < Output - class GitError < OxidizedError; end - begin - require 'rugged' - rescue LoadError - raise OxidizedError, 'rugged not found: sudo gem install rugged' - end - - attr_reader :commitref + class Git < Output + class GitError < OxidizedError; end + begin + require 'rugged' + rescue LoadError + raise OxidizedError, 'rugged not found: sudo gem install rugged' + end - def initialize - @cfg = Oxidized.config.output.git - end + attr_reader :commitref - def setup - if @cfg.empty? - Oxidized.asetus.user.output.git.user = 'Oxidized' - Oxidized.asetus.user.output.git.email = 'o@example.com' - Oxidized.asetus.user.output.git.repo = File.join(Config::Root, 'oxidized.git') - Oxidized.asetus.save :user - raise NoConfig, 'no output git config, edit ~/.config/oxidized/config' + def initialize + @cfg = Oxidized.config.output.git end - if @cfg.repo.respond_to?(:each) - @cfg.repo.each do |group, repo| - @cfg.repo["#{group}="] = File.expand_path repo + def setup + if @cfg.empty? + Oxidized.asetus.user.output.git.user = 'Oxidized' + Oxidized.asetus.user.output.git.email = 'o@example.com' + Oxidized.asetus.user.output.git.repo = File.join(Config::Root, 'oxidized.git') + Oxidized.asetus.save :user + raise NoConfig, 'no output git config, edit ~/.config/oxidized/config' end - else - @cfg.repo = File.expand_path @cfg.repo - end - end - def store file, outputs, opt={} - @msg = opt[:msg] - @user = (opt[:user] or @cfg.user) - @email = (opt[:email] or @cfg.email) - @opt = opt - @commitref = nil - repo = @cfg.repo - - outputs.types.each do |type| - type_cfg = '' - type_repo = File.join(File.dirname(repo), type + '.git') - outputs.type(type).each do |output| - (type_cfg << output; next) if not output.name - type_file = file + '--' + output.name - if @cfg.type_as_directory? - type_file = type + '/' + type_file - type_repo = repo + if @cfg.repo.respond_to?(:each) + @cfg.repo.each do |group, repo| + @cfg.repo["#{group}="] = File.expand_path repo end - update type_repo, type_file, output + else + @cfg.repo = File.expand_path @cfg.repo end - update type_repo, file, type_cfg end - update repo, file, outputs.to_cfg - end + def store file, outputs, opt = {} + @msg = opt[:msg] + @user = (opt[:user] or @cfg.user) + @email = (opt[:email] or @cfg.email) + @opt = opt + @commitref = nil + repo = @cfg.repo + + outputs.types.each do |type| + type_cfg = '' + type_repo = File.join(File.dirname(repo), type + '.git') + outputs.type(type).each do |output| + (type_cfg << output; next) if not output.name + type_file = file + '--' + output.name + if @cfg.type_as_directory? + type_file = type + '/' + type_file + type_repo = repo + end + update type_repo, type_file, output + end + update type_repo, file, type_cfg + end + update repo, file, outputs.to_cfg + end - def fetch node, group - begin - repo, path = yield_repo_and_path(node, group) - repo = Rugged::Repository.new repo - index = repo.index - index.read_tree repo.head.target.tree unless repo.empty? - repo.read(index.get(path)[:oid]).data - rescue - 'node not found' + def fetch node, group + begin + repo, path = yield_repo_and_path(node, group) + repo = Rugged::Repository.new repo + index = repo.index + index.read_tree repo.head.target.tree unless repo.empty? + repo.read(index.get(path)[:oid]).data + rescue + 'node not found' + end end - end # give a hash of all oid revision for the given node, and the date of the commit def version node, group @@ -80,7 +79,7 @@ class Git < Output walker.sorting(Rugged::SORT_DATE) walker.push(repo.head.target) i = -1 - tab = [] + tab = [] walker.each do |commit| if commit.diff(paths: [path]).size > 0 hash = {} @@ -98,18 +97,18 @@ class Git < Output end end - #give the blob of a specific revision + # give the blob of a specific revision def get_version node, group, oid begin repo, path = yield_repo_and_path(node, group) repo = Rugged::Repository.new repo - repo.blob_at(oid,path).content + repo.blob_at(oid, path).content rescue 'version not found' end end - #give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines) + # give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines) def get_diff node, group, oid1, oid2 begin diff_commits = nil @@ -122,15 +121,15 @@ class Git < Output diff = repo.diff(commit_old, commit) diff.each do |patch| if /#{node.name}\s+/.match(patch.to_s.lines.first) - diff_commits = {:patch => patch.to_s, :stat => patch.stat} + diff_commits = { :patch => patch.to_s, :stat => patch.stat } break end end else stat = commit.parents[0].diff(commit).stat - stat = [stat[1],stat[2]] + stat = [stat[1], stat[2]] patch = commit.parents[0].diff(commit).patch - diff_commits = {:patch => patch, :stat => stat} + diff_commits = { :patch => patch, :stat => stat } end diff_commits @@ -139,68 +138,67 @@ class Git < Output end end - private + private - def yield_repo_and_path(node, group) - repo, path = node.repo, node.name + def yield_repo_and_path(node, group) + repo, path = node.repo, node.name - if group and @cfg.single_repo? - path = "#{group}/#{node.name}" - end + if group and @cfg.single_repo? + path = "#{group}/#{node.name}" + end - [repo, path] - end + [repo, path] + end - def update repo, file, data - return if data.empty? + def update repo, file, data + return if data.empty? - if @opt[:group] - if @cfg.single_repo? - file = File.join @opt[:group], file - else - repo = if repo.is_a?(::String) - File.join File.dirname(repo), @opt[:group] + '.git' - else - repo[@opt[:group]] - end + if @opt[:group] + if @cfg.single_repo? + file = File.join @opt[:group], file + else + repo = if repo.is_a?(::String) + File.join File.dirname(repo), @opt[:group] + '.git' + else + repo[@opt[:group]] + end + end end - end - begin - repo = Rugged::Repository.new repo - update_repo repo, file, data, @msg, @user, @email - rescue Rugged::OSError, Rugged::RepositoryError => open_error begin - Rugged::Repository.init_at repo, :bare - rescue => create_error - raise GitError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo" + repo = Rugged::Repository.new repo + update_repo repo, file, data, @msg, @user, @email + rescue Rugged::OSError, Rugged::RepositoryError => open_error + begin + Rugged::Repository.init_at repo, :bare + rescue => create_error + raise GitError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo" + end + retry end - retry end - end - def update_repo repo, file, data, msg, user, email - oid = repo.write data, :blob - index = repo.index - index.read_tree repo.head.target.tree unless repo.empty? - - tree_old = index.write_tree repo - index.add :path=>file, :oid=>oid, :mode=>0100644 - tree_new = index.write_tree repo - - if tree_old != tree_new - repo.config['user.name'] = user - repo.config['user.email'] = email - @commitref = Rugged::Commit.create(repo, - :tree => index.write_tree(repo), - :message => msg, - :parents => repo.empty? ? [] : [repo.head.target].compact, - :update_ref => 'HEAD', - ) - - index.write - true + def update_repo repo, file, data, msg, user, email + oid = repo.write data, :blob + index = repo.index + index.read_tree repo.head.target.tree unless repo.empty? + + tree_old = index.write_tree repo + index.add :path => file, :oid => oid, :mode => 0100644 + tree_new = index.write_tree repo + + if tree_old != tree_new + repo.config['user.name'] = user + repo.config['user.email'] = email + @commitref = Rugged::Commit.create(repo, + :tree => index.write_tree(repo), + :message => msg, + :parents => repo.empty? ? [] : [repo.head.target].compact, + :update_ref => 'HEAD',) + + index.write + true + end end end end -end diff --git a/lib/oxidized/output/gitcrypt.rb b/lib/oxidized/output/gitcrypt.rb index b0d80f2..2da0179 100644 --- a/lib/oxidized/output/gitcrypt.rb +++ b/lib/oxidized/output/gitcrypt.rb @@ -1,244 +1,243 @@ module Oxidized - class GitCrypt < Output - class GitCryptError < OxidizedError; end - begin - require 'git' - rescue LoadError - raise OxidizedError, 'git not found: sudo gem install ruby-git' - end - - attr_reader :commitref - - def initialize - @cfg = Oxidized.config.output.gitcrypt - @gitcrypt_cmd = "/usr/bin/git-crypt" - @gitcrypt_init = @gitcrypt_cmd + " init" - @gitcrypt_unlock = @gitcrypt_cmd + " unlock" - @gitcrypt_lock = @gitcrypt_cmd + " lock" - @gitcrypt_adduser = @gitcrypt_cmd + " add-gpg-user --trusted " - end - - def setup - if @cfg.empty? - Oxidized.asetus.user.output.gitcrypt.user = 'Oxidized' - Oxidized.asetus.user.output.gitcrypt.email = 'o@example.com' - Oxidized.asetus.user.output.gitcrypt.repo = File.join(Config::Root, 'oxidized.git') - Oxidized.asetus.save :user - raise NoConfig, 'no output git config, edit ~/.config/oxidized/config' - end - - if @cfg.repo.respond_to?(:each) - @cfg.repo.each do |group, repo| - @cfg.repo["#{group}="] = File.expand_path repo - end - else - @cfg.repo = File.expand_path @cfg.repo - end - end - - def crypt_init repo - repo.chdir do - system(@gitcrypt_init) - @cfg.users.each do |user| - system("#{@gitcrypt_adduser} #{user}") - end - File.write(".gitattributes", "* filter=git-crypt diff=git-crypt\n.gitattributes !filter !diff") - repo.add(".gitattributes") - repo.commit("Initial commit: crypt all config files") - end - end - - def lock repo - repo.chdir do - system(@gitcrypt_lock) - end - end - - def unlock repo - repo.chdir do - system(@gitcrypt_unlock) - end - end - - def store file, outputs, opt={} - @msg = opt[:msg] - @user = (opt[:user] or @cfg.user) - @email = (opt[:email] or @cfg.email) - @opt = opt - @commitref = nil - repo = @cfg.repo - - outputs.types.each do |type| - type_cfg = '' - type_repo = File.join(File.dirname(repo), type + '.git') - outputs.type(type).each do |output| - (type_cfg << output; next) if not output.name - type_file = file + '--' + output.name - if @cfg.type_as_directory? - type_file = type + '/' + type_file - type_repo = repo - end - update type_repo, type_file, output - end - update type_repo, file, type_cfg - end - - update repo, file, outputs.to_cfg - end - - - def fetch node, group - begin - repo, path = yield_repo_and_path(node, group) - repo = Git.open repo - unlock repo - index = repo.index - # Empty repo ? - empty = File.exists? index.path - if empty - raise 'Empty git repo' - else - File.read path - end - lock repo - rescue - 'node not found' - end - end - - # give a hash of all oid revision for the given node, and the date of the commit - def version node, group - begin - repo, path = yield_repo_and_path(node, group) - - repo = Git.open repo - unlock repo - walker = repo.log.path(path) - i = -1 - tab = [] - walker.each do |commit| - hash = {} - hash[:date] = commit.date.to_s - hash[:oid] = commit.objectish - hash[:author] = commit.author - hash[:message] = commit.message - tab[i += 1] = hash - end - walker.reset - tab - rescue - 'node not found' - end - end - - #give the blob of a specific revision - def get_version node, group, oid - begin - repo, path = yield_repo_and_path(node, group) - repo = Git.open repo - unlock repo - repo.gtree(oid).files[path].contents - rescue - 'version not found' - ensure - lock repo - end - end - - #give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines) - def get_diff node, group, oid1, oid2 - begin - diff_commits = nil - repo, path = yield_repo_and_path(node, group) - repo = Git.open repo - unlock repo - commit = repo.gcommit(oid1) - - if oid2 - commit_old = repo.gcommit(oid2) - diff = repo.diff(commit_old, commit) - stats = [diff.stats[:files][node.name][:insertions], diff.stats[:files][node.name][:deletions]] - diff.each do |patch| - if /#{node.name}\s+/.match(patch.patch.to_s.lines.first) - diff_commits = {:patch => patch.patch.to_s, :stat => stats} - break - end - end - else - stat = commit.parents[0].diff(commit).stats - stat = [stat[:files][node.name][:insertions],stat[:files][node.name][:deletions]] - patch = commit.parents[0].diff(commit).patch - diff_commits = {:patch => patch, :stat => stat} - end - lock repo - diff_commits - rescue - 'no diffs' - ensure - lock repo - end - end - - private - - def yield_repo_and_path(node, group) - repo, path = node.repo, node.name - - if group and @cfg.single_repo? - path = "#{group}/#{node.name}" - end - - [repo, path] - end - - def update repo, file, data - return if data.empty? - - if @opt[:group] - if @cfg.single_repo? - file = File.join @opt[:group], file - else - repo = if repo.is_a?(::String) - File.join File.dirname(repo), @opt[:group] + '.git' - else - repo[@opt[:group]] - end - end - end - - begin - update_repo repo, file, data, @msg, @user, @email - rescue Git::GitExecuteError, ArgumentError => open_error - Oxidized.logger.debug "open_error #{open_error} #{file}" - begin - grepo = Git.init repo - crypt_init grepo - rescue => create_error - raise GitCryptError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo" - end - retry - end - end - - def update_repo repo, file, data, msg, user, email - grepo = Git.open repo - grepo.config('user.name', user) - grepo.config('user.email', email) - grepo.chdir do - unlock grepo - File.write(file, data) - grepo.add(file) - if grepo.status[file].nil? - grepo.commit(msg) - @commitref = grepo.log(1).first.objectish - true - elsif !grepo.status[file].type.nil? - grepo.commit(msg) - @commitref = grepo.log(1).first.objectish - true - end - lock grepo - end - end - end + class GitCrypt < Output + class GitCryptError < OxidizedError; end + begin + require 'git' + rescue LoadError + raise OxidizedError, 'git not found: sudo gem install ruby-git' + end + + attr_reader :commitref + + def initialize + @cfg = Oxidized.config.output.gitcrypt + @gitcrypt_cmd = "/usr/bin/git-crypt" + @gitcrypt_init = @gitcrypt_cmd + " init" + @gitcrypt_unlock = @gitcrypt_cmd + " unlock" + @gitcrypt_lock = @gitcrypt_cmd + " lock" + @gitcrypt_adduser = @gitcrypt_cmd + " add-gpg-user --trusted " + end + + def setup + if @cfg.empty? + Oxidized.asetus.user.output.gitcrypt.user = 'Oxidized' + Oxidized.asetus.user.output.gitcrypt.email = 'o@example.com' + Oxidized.asetus.user.output.gitcrypt.repo = File.join(Config::Root, 'oxidized.git') + Oxidized.asetus.save :user + raise NoConfig, 'no output git config, edit ~/.config/oxidized/config' + end + + if @cfg.repo.respond_to?(:each) + @cfg.repo.each do |group, repo| + @cfg.repo["#{group}="] = File.expand_path repo + end + else + @cfg.repo = File.expand_path @cfg.repo + end + end + + def crypt_init repo + repo.chdir do + system(@gitcrypt_init) + @cfg.users.each do |user| + system("#{@gitcrypt_adduser} #{user}") + end + File.write(".gitattributes", "* filter=git-crypt diff=git-crypt\n.gitattributes !filter !diff") + repo.add(".gitattributes") + repo.commit("Initial commit: crypt all config files") + end + end + + def lock repo + repo.chdir do + system(@gitcrypt_lock) + end + end + + def unlock repo + repo.chdir do + system(@gitcrypt_unlock) + end + end + + def store file, outputs, opt = {} + @msg = opt[:msg] + @user = (opt[:user] or @cfg.user) + @email = (opt[:email] or @cfg.email) + @opt = opt + @commitref = nil + repo = @cfg.repo + + outputs.types.each do |type| + type_cfg = '' + type_repo = File.join(File.dirname(repo), type + '.git') + outputs.type(type).each do |output| + (type_cfg << output; next) if not output.name + type_file = file + '--' + output.name + if @cfg.type_as_directory? + type_file = type + '/' + type_file + type_repo = repo + end + update type_repo, type_file, output + end + update type_repo, file, type_cfg + end + + update repo, file, outputs.to_cfg + end + + def fetch node, group + begin + repo, path = yield_repo_and_path(node, group) + repo = Git.open repo + unlock repo + index = repo.index + # Empty repo ? + empty = File.exists? index.path + if empty + raise 'Empty git repo' + else + File.read path + end + lock repo + rescue + 'node not found' + end + end + + # give a hash of all oid revision for the given node, and the date of the commit + def version node, group + begin + repo, path = yield_repo_and_path(node, group) + + repo = Git.open repo + unlock repo + walker = repo.log.path(path) + i = -1 + tab = [] + walker.each do |commit| + hash = {} + hash[:date] = commit.date.to_s + hash[:oid] = commit.objectish + hash[:author] = commit.author + hash[:message] = commit.message + tab[i += 1] = hash + end + walker.reset + tab + rescue + 'node not found' + end + end + + # give the blob of a specific revision + def get_version node, group, oid + begin + repo, path = yield_repo_and_path(node, group) + repo = Git.open repo + unlock repo + repo.gtree(oid).files[path].contents + rescue + 'version not found' + ensure + lock repo + end + end + + # give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines) + def get_diff node, group, oid1, oid2 + begin + diff_commits = nil + repo, path = yield_repo_and_path(node, group) + repo = Git.open repo + unlock repo + commit = repo.gcommit(oid1) + + if oid2 + commit_old = repo.gcommit(oid2) + diff = repo.diff(commit_old, commit) + stats = [diff.stats[:files][node.name][:insertions], diff.stats[:files][node.name][:deletions]] + diff.each do |patch| + if /#{node.name}\s+/.match(patch.patch.to_s.lines.first) + diff_commits = { :patch => patch.patch.to_s, :stat => stats } + break + end + end + else + stat = commit.parents[0].diff(commit).stats + stat = [stat[:files][node.name][:insertions], stat[:files][node.name][:deletions]] + patch = commit.parents[0].diff(commit).patch + diff_commits = { :patch => patch, :stat => stat } + end + lock repo + diff_commits + rescue + 'no diffs' + ensure + lock repo + end + end + + private + + def yield_repo_and_path(node, group) + repo, path = node.repo, node.name + + if group and @cfg.single_repo? + path = "#{group}/#{node.name}" + end + + [repo, path] + end + + def update repo, file, data + return if data.empty? + + if @opt[:group] + if @cfg.single_repo? + file = File.join @opt[:group], file + else + repo = if repo.is_a?(::String) + File.join File.dirname(repo), @opt[:group] + '.git' + else + repo[@opt[:group]] + end + end + end + + begin + update_repo repo, file, data, @msg, @user, @email + rescue Git::GitExecuteError, ArgumentError => open_error + Oxidized.logger.debug "open_error #{open_error} #{file}" + begin + grepo = Git.init repo + crypt_init grepo + rescue => create_error + raise GitCryptError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo" + end + retry + end + end + + def update_repo repo, file, data, msg, user, email + grepo = Git.open repo + grepo.config('user.name', user) + grepo.config('user.email', email) + grepo.chdir do + unlock grepo + File.write(file, data) + grepo.add(file) + if grepo.status[file].nil? + grepo.commit(msg) + @commitref = grepo.log(1).first.objectish + true + elsif !grepo.status[file].type.nil? + grepo.commit(msg) + @commitref = grepo.log(1).first.objectish + true + end + lock grepo + end + end + end end diff --git a/lib/oxidized/output/http.rb b/lib/oxidized/output/http.rb index 13ba300..0467261 100644 --- a/lib/oxidized/output/http.rb +++ b/lib/oxidized/output/http.rb @@ -7,9 +7,9 @@ module Oxidized def setup if @cfg.empty? - CFGS.user.output.http.user = 'Oxidized' + CFGS.user.output.http.user = 'Oxidized' CFGS.user.output.http.pasword = 'secret' - CFGS.user.output.http.url = 'http://localhost/web-api/oxidized' + CFGS.user.output.http.url = 'http://localhost/web-api/oxidized' CFGS.save :user raise NoConfig, 'no output http config, edit ~/.config/oxidized/config' end @@ -17,42 +17,38 @@ module Oxidized require "net/http" require "uri" require "json" - def store node, outputs, opt={} + def store node, outputs, opt = {} @commitref = nil json = JSON.pretty_generate( - { - 'msg' => opt[:msg], - 'user' => opt[:user], - 'email' => opt[:email], - 'group' => opt[:group], - 'node' => node, - 'config' => outputs.to_cfg, - # actually we need to also iterate outputs, for other types like in gitlab. But most people don't use 'type' functionality. - } + { + 'msg' => opt[:msg], + 'user' => opt[:user], + 'email' => opt[:email], + 'group' => opt[:group], + 'node' => node, + 'config' => outputs.to_cfg, + # actually we need to also iterate outputs, for other types like in gitlab. But most people don't use 'type' functionality. + } ) uri = URI.parse @cfg.url http = Net::HTTP.new uri.host, uri.port - #http.use_ssl = true if uri.scheme = 'https' - req = Net::HTTP::Post.new(uri.request_uri, initheader = { 'Content-Type' => 'application/json'}) + # http.use_ssl = true if uri.scheme = 'https' + req = Net::HTTP::Post.new(uri.request_uri, initheader = { 'Content-Type' => 'application/json' }) req.basic_auth @cfg.user, @cfg.password req.body = json response = http.request req case response.code.to_i - when 200 || 201 - Oxidized.logger.info "Configuration http backup complete for #{node}" - p [:success] - when (400..499) - Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}" - p [:bad_request] - when (500..599) - p [:server_problems] - Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}" + when 200 || 201 + Oxidized.logger.info "Configuration http backup complete for #{node}" + p [:success] + when (400..499) + Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}" + p [:bad_request] + when (500..599) + p [:server_problems] + Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}" end - end - end end - - diff --git a/lib/oxidized/output/output.rb b/lib/oxidized/output/output.rb index 1355d03..9fae7b0 100644 --- a/lib/oxidized/output/output.rb +++ b/lib/oxidized/output/output.rb @@ -3,8 +3,7 @@ module Oxidized class NoConfig < OxidizedError; end def cfg_to_str cfg - cfg.select{ |h| h[:type]=='cfg' }.map{ |h| h[:data] }.join + cfg.select { |h| h[:type] == 'cfg' }.map { |h| h[:data] }.join end - end end diff --git a/lib/oxidized/source/csv.rb b/lib/oxidized/source/csv.rb index 4814bd7..7b771f6 100644 --- a/lib/oxidized/source/csv.rb +++ b/lib/oxidized/source/csv.rb @@ -1,54 +1,53 @@ module Oxidized -class CSV < Source - def initialize - @cfg = Oxidized.config.source.csv - super - end - - def setup - if @cfg.empty? - Oxidized.asetus.user.source.csv.file = File.join(Config::Root, 'router.db') - Oxidized.asetus.user.source.csv.delimiter = /:/ - Oxidized.asetus.user.source.csv.map.name = 0 - Oxidized.asetus.user.source.csv.map.model = 1 - Oxidized.asetus.user.source.csv.gpg = false - Oxidized.asetus.save :user - raise NoConfig, 'no source csv config, edit ~/.config/oxidized/config' + class CSV < Source + def initialize + @cfg = Oxidized.config.source.csv + super end - require 'gpgme' if @cfg.gpg? - end - def load - nodes = [] - file = File.expand_path(@cfg.file) - file = if @cfg.gpg? - crypto = GPGME::Crypto.new password: @cfg.gpg_password - file = crypto.decrypt(File.open(file)).to_s - else - open(file) - end - file.each_line do |line| - next if line.match(/^\s*#/) - data = line.chomp.split(@cfg.delimiter, -1) - next if data.empty? - # map node parameters - keys = {} - @cfg.map.each do |key, position| - keys[key.to_sym] = node_var_interpolate data[position] + def setup + if @cfg.empty? + Oxidized.asetus.user.source.csv.file = File.join(Config::Root, 'router.db') + Oxidized.asetus.user.source.csv.delimiter = /:/ + Oxidized.asetus.user.source.csv.map.name = 0 + Oxidized.asetus.user.source.csv.map.model = 1 + Oxidized.asetus.user.source.csv.gpg = false + Oxidized.asetus.save :user + raise NoConfig, 'no source csv config, edit ~/.config/oxidized/config' end - keys[:model] = map_model keys[:model] if keys.key? :model + require 'gpgme' if @cfg.gpg? + end - # map node specific vars - vars = {} - @cfg.vars_map.each do |key, position| - vars[key.to_sym] = node_var_interpolate data[position] - end - keys[:vars] = vars unless vars.empty? + def load _node_want = nil + nodes = [] + file = File.expand_path(@cfg.file) + file = if @cfg.gpg? + crypto = GPGME::Crypto.new password: @cfg.gpg_password + file = crypto.decrypt(File.open(file)).to_s + else + open(file) + end + file.each_line do |line| + next if line.match(/^\s*#/) + data = line.chomp.split(@cfg.delimiter, -1) + next if data.empty? + # map node parameters + keys = {} + @cfg.map.each do |key, position| + keys[key.to_sym] = node_var_interpolate data[position] + end + keys[:model] = map_model keys[:model] if keys.has_key? :model - nodes << keys + # map node specific vars + vars = {} + @cfg.vars_map.each do |key, position| + vars[key.to_sym] = node_var_interpolate data[position] + end + keys[:vars] = vars unless vars.empty? + + nodes << keys + end + nodes end - nodes end - -end end diff --git a/lib/oxidized/source/http.rb b/lib/oxidized/source/http.rb index 6c12f29..55dcd4c 100644 --- a/lib/oxidized/source/http.rb +++ b/lib/oxidized/source/http.rb @@ -1,64 +1,67 @@ module Oxidized -class HTTP < Source - def initialize - @cfg = Oxidized.config.source.http - super - end - - def setup - if @cfg.url.empty? - raise NoConfig, 'no source http url config, edit ~/.config/oxidized/config' + class HTTP < Source + def initialize + @cfg = Oxidized.config.source.http + super end - end - - require "net/http" - require "uri" - require "json" - def load - nodes = [] - uri = URI.parse(@cfg.url) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true if uri.scheme == 'https' - http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @cfg.secure - - # map headers - headers = {} - @cfg.headers.each do |header, value| - headers[header] = value + def setup + if @cfg.url.empty? + raise NoConfig, 'no source http url config, edit ~/.config/oxidized/config' + end end - request = Net::HTTP::Get.new(uri.request_uri, headers) - if (@cfg.user? && @cfg.pass?) - request.basic_auth(@cfg.user,@cfg.pass) - end + require "net/http" + require "uri" + require "json" - response = http.request(request) - data = JSON.parse(response.body) - data.each do |node| - next if node.empty? - # map node parameters - keys = {} - @cfg.map.each do |key, want_position| - want_positions = want_position.split('.') - keys[key.to_sym] = node_var_interpolate node.dig(*want_positions) + def load node_want = nil + nodes = [] + uri = URI.parse(@cfg.url) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true if uri.scheme == 'https' + http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @cfg.secure + + # map headers + headers = {} + @cfg.headers.each do |header, value| + headers[header] = value end - keys[:model] = map_model keys[:model] if keys.key? :model - # map node specific vars - vars = {} - @cfg.vars_map.each do |key, want_position| - want_positions = want_position.split('.') - vars[key.to_sym] = node_var_interpolate node.dig(*want_positions) + req_uri = uri.request_uri + if node_want + req_uri = "#{req_uri}/#{node_want}" + end + request = Net::HTTP::Get.new(req_uri, headers) + if (@cfg.user? && @cfg.pass?) + request.basic_auth(@cfg.user, @cfg.pass) end - keys[:vars] = vars unless vars.empty? - nodes << keys + response = http.request(request) + data = JSON.parse(response.body) + data.each do |node| + next if node.empty? + # map node parameters + keys = {} + @cfg.map.each do |key, want_position| + want_positions = want_position.split('.') + keys[key.to_sym] = node_var_interpolate node.dig(*want_positions) + end + keys[:model] = map_model keys[:model] if keys.has_key? :model + + # map node specific vars + vars = {} + @cfg.vars_map.each do |key, want_position| + want_positions = want_position.split('.') + vars[key.to_sym] = node_var_interpolate node.dig(*want_positions) + end + keys[:vars] = vars unless vars.empty? + + nodes << keys + end + nodes end - nodes end - -end end if RUBY_VERSION < '2.3' diff --git a/lib/oxidized/source/source.rb b/lib/oxidized/source/source.rb index 9b8bc94..3bae0f6 100644 --- a/lib/oxidized/source/source.rb +++ b/lib/oxidized/source/source.rb @@ -11,13 +11,12 @@ module Oxidized end def node_var_interpolate var - case var - when "nil" then nil - when "false" then false - when "true" then true - else var - end + case var + when "nil" then nil + when "false" then false + when "true" then true + else var + end end - end end diff --git a/lib/oxidized/source/sql.rb b/lib/oxidized/source/sql.rb index 13fc39b..c5fe650 100644 --- a/lib/oxidized/source/sql.rb +++ b/lib/oxidized/source/sql.rb @@ -1,63 +1,67 @@ module Oxidized -class SQL < Source - begin - require 'sequel' - rescue LoadError - raise OxidizedError, 'sequel not found: sudo gem install sequel' - end + class SQL < Source + begin + require 'sequel' + rescue LoadError + raise OxidizedError, 'sequel not found: sudo gem install sequel' + end - def setup - if @cfg.empty? - Oxidized.asetus.user.source.sql.adapter = 'sqlite' - Oxidized.asetus.user.source.sql.database = File.join(Config::Root, 'sqlite.db') - Oxidized.asetus.user.source.sql.table = 'devices' - Oxidized.asetus.user.source.sql.map.name = 'name' - Oxidized.asetus.user.source.sql.map.model = 'rancid' - Oxidized.asetus.save :user - raise NoConfig, 'no source sql config, edit ~/.config/oxidized/config' + def setup + if @cfg.empty? + Oxidized.asetus.user.source.sql.adapter = 'sqlite' + Oxidized.asetus.user.source.sql.database = File.join(Config::Root, 'sqlite.db') + Oxidized.asetus.user.source.sql.table = 'devices' + Oxidized.asetus.user.source.sql.map.name = 'name' + Oxidized.asetus.user.source.sql.map.model = 'rancid' + Oxidized.asetus.save :user + raise NoConfig, 'no source sql config, edit ~/.config/oxidized/config' + end end - end - def load - nodes = [] - db = connect - query = db[@cfg.table.to_sym] - query = query.with_sql(@cfg.query) if @cfg.query? - query.each do |node| - # map node parameters - keys = {} - @cfg.map.each { |key, sql_column| keys[key.to_sym] = node_var_interpolate node[sql_column.to_sym] } - keys[:model] = map_model keys[:model] if keys.key? :model - - # map node specific vars - vars = {} - @cfg.vars_map.each do |key, sql_column| - vars[key.to_sym] = node_var_interpolate node[sql_column.to_sym] + def load node_want = nil + nodes = [] + db = connect + query = db[@cfg.table.to_sym] + query = query.with_sql(@cfg.query) if @cfg.query? + + if node_want + query = query.where(@cfg.map.name.to_sym => node_want) end - keys[:vars] = vars unless vars.empty? - nodes << keys + query.each do |node| + # map node parameters + keys = {} + @cfg.map.each { |key, sql_column| keys[key.to_sym] = node_var_interpolate node[sql_column.to_sym] } + keys[:model] = map_model keys[:model] if keys.has_key? :model + + # map node specific vars + vars = {} + @cfg.vars_map.each do |key, sql_column| + vars[key.to_sym] = node_var_interpolate node[sql_column.to_sym] + end + keys[:vars] = vars unless vars.empty? + + nodes << keys + end + db.disconnect + nodes end - db.disconnect - nodes - end - private + private - def initialize - super - @cfg = Oxidized.config.source.sql - end + def initialize + super + @cfg = Oxidized.config.source.sql + end - def connect - Sequel.connect(:adapter => @cfg.adapter, - :host => @cfg.host?, - :user => @cfg.user?, - :password => @cfg.password?, - :database => @cfg.database) - rescue Sequel::AdapterNotFound => error - raise OxidizedError, "SQL adapter gem not installed: " + error.message + def connect + Sequel.connect(:adapter => @cfg.adapter, + :host => @cfg.host?, + :user => @cfg.user?, + :password => @cfg.password?, + :database => @cfg.database) + rescue Sequel::AdapterNotFound => error + raise OxidizedError, "SQL adapter gem not installed: " + error.message + end end - -end end diff --git a/lib/oxidized/string.rb b/lib/oxidized/string.rb index 8bcb082..ca4862d 100644 --- a/lib/oxidized/string.rb +++ b/lib/oxidized/string.rb @@ -15,11 +15,11 @@ module Oxidized # sets @cmd and @name unless @name is already set def set_cmd command - @cmd = command + @cmd = command @name ||= @cmd.strip.gsub(/\s+/, '_') end - def initialize str='' + def initialize str = '' super if str.class == Oxidized::String @cmd = str.cmd @@ -27,6 +27,5 @@ module Oxidized @type = str.type end end - end end diff --git a/lib/oxidized/version.rb b/lib/oxidized/version.rb index 9a92133..b607e12 100644 --- a/lib/oxidized/version.rb +++ b/lib/oxidized/version.rb @@ -1,3 +1,19 @@ module Oxidized VERSION = '0.21.0' + VERSION_FULL = '0.21.0-180-g9691008' + def self.version_set + version_full = %x(git describe --tags).chop rescue "" + version = %x(git describe --tags --abbrev=0).chop rescue "" + + return false unless [version, version_full].none?(&:empty?) + + Oxidized.send(:remove_const, :VERSION) + Oxidized.send(:remove_const, :VERSION_FULL) + const_set(:VERSION, version) + const_set(:VERSION_FULL, version_full) + file = File.readlines(__FILE__) + file[1] = " VERSION = '%s'\n" % VERSION + file[2] = " VERSION_FULL = '%s'\n" % VERSION_FULL + File.write(__FILE__, file.join) + end end diff --git a/lib/oxidized/worker.rb b/lib/oxidized/worker.rb index 4173680..5d5fc01 100644 --- a/lib/oxidized/worker.rb +++ b/lib/oxidized/worker.rb @@ -42,9 +42,9 @@ module Oxidized node.stats.add job @jobs.duration job.time node.running = false - @jobs_done += 1 # needed for worker_done event if job.status == :success + @jobs_done += 1 # needed for :nodes_done hook Oxidized.Hooks.handle :node_success, :node => node, :job => job msg = "update #{node.name}" @@ -52,7 +52,7 @@ module Oxidized msg += " with message '#{node.msg}'" if node.msg output = node.output.new if output.store node.name, job.config, - :msg => msg, :email => node.email, :user => node.user, :group => node.group + :msg => msg, :email => node.email, :user => node.user, :group => node.group Oxidized.logger.info "Configuration updated for #{node.group}/#{node.name}" Oxidized.Hooks.handle :post_store, :node => node, :job => job, @@ -66,6 +66,11 @@ module Oxidized msg += ", retry attempt #{node.retry}" @nodes.next node.name else + # Only increment the @jobs_done when we give up retries for a node (or success). + # As it would otherwise cause @jobs_done to be incremented with generic retries. + # This would cause :nodes_done hook to desync from running at the end of the nodelist and + # be fired when the @jobs_done > @nodes.count (could be mid-cycle on the next cycle). + @jobs_done += 1 msg += ", retries exhausted, giving up" node.retry = 0 Oxidized.Hooks.handle :node_fail, :node => node, @@ -80,7 +85,11 @@ module Oxidized private def is_cycle_finished? - @jobs_done > 0 && @jobs_done % @nodes.count == 0 + if @jobs_done > @nodes.count + true + else + @jobs_done > 0 && @jobs_done % @nodes.count == 0 + end end def run_done_hook |