├── .gitignore ├── Gemfile ├── lib └── oxidized │ ├── script.rb │ └── script │ ├── command.rb │ ├── commands │ ├── list-models.rb │ └── list-nodes.rb │ ├── script.rb │ └── cli.rb ├── bin └── oxs ├── TODO.md ├── .rubocop.yml ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── workflows │ ├── stale.yml │ ├── publishdocker.yml │ ├── ruby.yml │ └── codeql.yml └── dependabot.yml ├── Rakefile ├── oxidized-script.gemspec ├── CHANGELOG.md ├── README.md └── .rubocop_todo.yml /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | pkg 3 | *.swp 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /lib/oxidized/script.rb: -------------------------------------------------------------------------------- 1 | require_relative 'script/script' 2 | -------------------------------------------------------------------------------- /lib/oxidized/script/command.rb: -------------------------------------------------------------------------------- 1 | module Oxidized 2 | class Script 3 | module Command 4 | class Base 5 | end 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /bin/oxs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | begin 4 | require 'oxidized/script/cli' 5 | Oxidized::Script::CLI.new.run 6 | rescue => error 7 | warn "#{error}" 8 | raise if Oxidized.config.debug 9 | end 10 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # To Do 2 | 3 | ## Features 4 | 5 | - issues/7: provide interactive oxs shell 6 | - issues/13: Option to provide alternative router.db file for scripts usage 7 | - issues/19: print name of the command when executing oxs 8 | - issues/32: handle a confirm prompt with oxidized-script -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | AllCops: 4 | NewCops: enable 5 | TargetRubyVersion: 3.2 6 | 7 | Lint/RaiseException: 8 | Enabled: true 9 | 10 | Lint/StructNewOverride: 11 | Enabled: true 12 | 13 | Style/HashEachMethods: 14 | Enabled: true 15 | 16 | Style/HashTransformKeys: 17 | Enabled: true 18 | 19 | Style/HashTransformValues: 20 | Enabled: true 21 | 22 | require: 23 | - rubocop-rake 24 | - rubocop-minitest 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Pre-Request Checklist 2 | 3 | 4 | - [ ] Passes rubocop code analysis (try `rubocop --auto-correct`) 5 | - [ ] Tests added or adapted (try `rake test`) 6 | - [ ] Changes are reflected in the documentation 7 | - [ ] User-visible changes appended to [CHANGELOG.md](/CHANGELOG.md) 8 | 9 | ## Description 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Stale Issue/PR cleanup" 3 | on: 4 | schedule: 5 | - cron: "30 1 * * *" 6 | 7 | permissions: 8 | issues: write 9 | pull-requests: write 10 | 11 | jobs: 12 | stale: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/stale@v9 16 | with: 17 | stale-issue-message: 'This issue is stale because it has been open 90 days with no activity.' 18 | stale-pr-message: 'This PR is stale because it has been open 90 days with no activity.' 19 | operations-per-run: 500 20 | days-before-stale: 90 21 | days-before-close: -1 22 | -------------------------------------------------------------------------------- /lib/oxidized/script/commands/list-models.rb: -------------------------------------------------------------------------------- 1 | module Oxidized 2 | class Script 3 | module Command 4 | class ListModels < Base 5 | Name = 'list-models' 6 | Description = 'list supported models' 7 | 8 | def self.run opts={} 9 | puts new(opts).models 10 | end 11 | 12 | def models 13 | out = '' 14 | models = Dir.glob File.join Config::MODEL_DIR, '*.rb' 15 | models.each do |model| 16 | out += "%15s - %s\n" % [File.basename(model, '.rb'), model] 17 | end 18 | out 19 | end 20 | 21 | private 22 | 23 | def initialize opts={} 24 | end 25 | 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /.github/workflows/publishdocker.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker 2 | on: 3 | push: 4 | branches: [ "master" ] 5 | jobs: 6 | build: 7 | if: github.repository_owner == 'ytti' 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@master 11 | with: 12 | fetch-depth: 0 13 | - name: Get Release Version 14 | id: get_version 15 | run: echo "release-version=$(git describe --tags)" >> $GITHUB_OUTPUT 16 | - name: Set up Docker Buildx 17 | uses: docker/setup-buildx-action@v3 18 | - name: Publish to Registry 19 | uses: elgohr/Publish-Docker-Github-Action@v5 20 | with: 21 | name: oxidized/oxidized 22 | username: ${{ secrets.DOCKER_USERNAME }} 23 | password: ${{ secrets.DOCKER_PASSWORD }} 24 | tags: "latest,${{ steps.get_version.outputs.release-version }}" 25 | platforms: linux/amd64,linux/arm64 26 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | target-branch: "master" 10 | directory: "/" 11 | schedule: 12 | interval: "daily" 13 | open-pull-requests-limit: 10 14 | labels: 15 | - dependencies 16 | - package-ecosystem: "bundler" 17 | target-branch: "master" 18 | directory: "/" 19 | schedule: 20 | interval: "daily" 21 | open-pull-requests-limit: 10 22 | labels: 23 | - dependencies 24 | - package-ecosystem: "docker" 25 | target-branch: "master" 26 | directory: "/" 27 | schedule: 28 | interval: "daily" 29 | open-pull-requests-limit: 10 30 | labels: 31 | - dependencies 32 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/testtask' 3 | 4 | gemspec = eval(File.read(Dir['*.gemspec'].first)) 5 | gemfile = [gemspec.name, gemspec.version].join('-') + '.gem' 6 | 7 | desc 'Validate gemspec' 8 | task :gemspec do 9 | gemspec.validate 10 | end 11 | 12 | desc 'Run minitest' 13 | task :test do 14 | Rake::TestTask.new do |t| 15 | t.libs << 'spec' 16 | t.test_files = FileList['spec/**/*_spec.rb'] 17 | t.warning = true 18 | t.verbose = true 19 | end 20 | end 21 | 22 | desc 'Install gem' 23 | task install: :build do 24 | system "sudo -Es sh -c 'umask 022; gem install gems/#{gemfile}'" 25 | end 26 | 27 | task build: :chmod 28 | desc 'Remove gems' 29 | task :clean do 30 | FileUtils.rm_rf 'pkg' 31 | end 32 | 33 | desc 'Tag the release' 34 | task :tag do 35 | system "git tag #{gemspec.version}" 36 | end 37 | 38 | desc 'Push to rubygems' 39 | task push: :tag do 40 | system "gem push pkg/#{gemfile}" 41 | end 42 | 43 | desc 'Normalise file permissions' 44 | task :chmod do 45 | xbit = %w[ 46 | bin/oxs 47 | ] 48 | dirs = [] 49 | %x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }.each do |file| 50 | dirs.push(File.dirname(file)) 51 | xbit.include?(file) ? File.chmod(0o0755, file) : File.chmod(0o0644, file) 52 | end 53 | dirs.sort.uniq.each { |dir| File.chmod(0o0755, dir) } 54 | end 55 | 56 | task default: :test 57 | -------------------------------------------------------------------------------- /oxidized-script.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'oxidized-script' 3 | s.version = '0.7.0' 4 | s.licenses = %w[Apache-2.0] 5 | s.platform = Gem::Platform::RUBY 6 | s.authors = ['Saku Ytti'] 7 | s.email = %w[saku@ytti.fi] 8 | s.homepage = 'http://github.com/ytti/oxidized-script' 9 | s.summary = 'cli + library for scripting network devices' 10 | s.description = 'rancid clogin-like script to push configs to devices + library interface to do same' 11 | s.files = `git ls-files -z`.split("\x0") 12 | s.executables = %w[oxs] 13 | s.require_path = 'lib' 14 | 15 | s.metadata['rubygems_mfa_required'] = 'true' 16 | 17 | s.required_ruby_version = '>= 3.0' 18 | 19 | s.add_runtime_dependency 'oxidized', '~> 0.29' 20 | s.add_runtime_dependency 'slop', '~> 4.6' 21 | 22 | s.add_development_dependency 'bundler', '~> 2.2' 23 | s.add_development_dependency 'rake', '~> 13.0' 24 | s.add_development_dependency 'rubocop', '~> 1.71.0' 25 | s.add_development_dependency 'rubocop-minitest', '~> 0.36.0' 26 | s.add_development_dependency 'rubocop-rake', '~> 0.6.0' 27 | s.add_development_dependency 'simplecov', '~> 0.22.0' 28 | s.add_development_dependency 'simplecov-cobertura', '~> 2.1.0' 29 | s.add_development_dependency 'simplecov-html', '~> 0.13.1' 30 | end 31 | -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake 6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby 7 | 8 | name: CI 9 | 10 | on: [ push, pull_request ] 11 | # push: 12 | # branches: [ master ] 13 | # pull_request: 14 | # branches: [ master ] 15 | 16 | jobs: 17 | test: 18 | 19 | runs-on: ubuntu-latest 20 | strategy: 21 | matrix: 22 | ruby-version: ['3.1', '3.2', '3.3', '3.4', 'ruby-head'] 23 | continue-on-error: ${{ matrix.ruby-version == 'ruby-head' }} 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Set up Ruby 28 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, 29 | # change this to (see https://github.com/ruby/setup-ruby#versioning): 30 | uses: ruby/setup-ruby@v1 31 | with: 32 | ruby-version: ${{ matrix.ruby-version }} 33 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 34 | - name: rubocop 35 | uses: reviewdog/action-rubocop@v2 36 | with: 37 | rubocop_version: gemfile 38 | rubocop_extensions: rubocop-minitest:gemfile rubocop-rake:gemfile 39 | reporter: github-pr-review 40 | - name: Run tests 41 | run: bundle exec rake 42 | - uses: codecov/codecov-action@v5 43 | if: ${{ always() }} 44 | -------------------------------------------------------------------------------- /lib/oxidized/script/commands/list-nodes.rb: -------------------------------------------------------------------------------- 1 | module Oxidized 2 | class Script 3 | module Command 4 | class ListNodes < Base 5 | Name = 'list-nodes' 6 | Description = 'list nodes in oxidized source' 7 | 8 | # this is not needed this this command, just shown how todo more 9 | # complex commands, this could use slop sub-commands etc. As long as it 10 | # sets cli.cmd_class when you want to run it, it gets ran after parsing 11 | # commandline 12 | def self.cmdline slop, cli 13 | slop.on "--#{Name}", Description do 14 | cli.cmd_class = self 15 | end 16 | end 17 | 18 | def self.run opts={} 19 | if opts[:opts][:terse] # find if 'terse' global option is set 20 | puts new(opts).nodes_terse 21 | else 22 | puts new(opts).nodes 23 | end 24 | end 25 | 26 | def nodes 27 | out = '' 28 | Nodes.new.each do |node| 29 | out += "#{node.name}:\n" 30 | node.instance_variables.each do |var| 31 | name = var.to_s[1..-1] 32 | next if name == 'name' 33 | value = node.instance_variable_get var 34 | value = value.class if name == 'model' 35 | out += " %10s => %s\n" % [name, value.to_s] 36 | end 37 | end 38 | out 39 | end 40 | 41 | def nodes_terse 42 | out = '' 43 | i = 0 44 | Nodes.new.each do |node| 45 | out += "#{i += 1} - #{node.name}\n" 46 | end 47 | out 48 | end 49 | 50 | private 51 | 52 | def initialize opts={} 53 | Oxidized.mgr = Manager.new 54 | end 55 | 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). 4 | 5 | ## [Unreleased] 6 | 7 | ### Added 8 | - TODO.md - a list of future aspirations for some brave spirit with both time and willingness 9 | 10 | ### Fixed 11 | - fixed --list-models (@nickhilliard) 12 | - return exception if host specification line returns no hosts (@nickhilliard) 13 | - Remove Oxidized.setup_logger from CLI initialization (@nickhilliard) 14 | 15 | ## [0.7.0 - 2025-01-21] 16 | 17 | ### Added 18 | - Added no-trim option (@Gman98ish) 19 | - added rubocop config (@wk) 20 | - added Github Actions from ytti/oxidized (@aschaber1) 21 | 22 | ### Fixed 23 | - Normalise file permissions before push (@ytti) 24 | - update gemspec dependencies (@nickhilliard) 25 | - updates + sanity checking on gh actions (@nickhilliard) 26 | 27 | ## [0.6.0 - 2018-12-16] 28 | 29 | ### Added 30 | - Implemented combination of regex with ostype (@LarsKollstedt) 31 | 32 | ### Fixed 33 | - refactor some code (@ytti) 34 | - updated oxidized dependency (@ytti) 35 | 36 | ## [0.5.1 - 2018-06-03] 37 | 38 | ### Fixed 39 | - fixed oxidized dependency (@ytti) 40 | 41 | ## [0.5.0 - 2017-11-01] 42 | 43 | ### Fixed 44 | - adding in sync for stdout giving more control over individual changes (@nertwork) 45 | 46 | ## 0.4.0 47 | - FEATURE on --ostype to get a list of nodes that match a particular OS Type (junos, routeros, ios) (by InsaneSplash) 48 | 49 | ## 0.3.1 50 | - FEATURE on --dryrun to get a list of nodes without running a command (by @nertwork) 51 | - BUGFIX: errors with large config files running in ruby threads - forking instead (by @nertwork) 52 | 53 | ## 0.3.0 54 | - FEATURE on --regex to run commands on hosts matching a regex (by @nertwork) 55 | - FEATURE on -g to run commands on entire group (by @nertwork) 56 | - FEATURE on -r to thread commands run on entire group (by @nertwork) 57 | - BUGFIX: fix for replacing escaped newlines in config files (by @nertwork) 58 | 59 | ## 0.2.0 60 | - FEATURE on -x disable ssh exec mode (by @nickhilliard) 61 | 62 | ## 0.1.2 63 | - BUGFIX: fix for oxidized refactored code 64 | 65 | ## 0.1.1 66 | - BUGFIX: initialize manager only once 67 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '44 21 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'ruby' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | 54 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 55 | # queries: security-extended,security-and-quality 56 | 57 | 58 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 59 | # If this step fails, then you should remove it and run the build manually (see below) 60 | - name: Autobuild 61 | uses: github/codeql-action/autobuild@v3 62 | 63 | # ℹ️ Command-line programs to run using the OS shell. 64 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 65 | 66 | # If the Autobuild fails above, remove it and uncomment the following three lines. 67 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 68 | 69 | # - run: | 70 | # echo "Run, Build Application using script" 71 | # ./location_of_script_within_repo/buildscript.sh 72 | 73 | - name: Perform CodeQL Analysis 74 | uses: github/codeql-action/analyze@v3 75 | with: 76 | category: "/language:${{matrix.language}}" 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Oxidized Script 2 | CLI and Library to interface with network devices in Oxidized 3 | 4 | ## Install 5 | % gem install oxidized-script 6 | 7 | ## Use 8 | 9 | ### CLI 10 | ``` 11 | [fisakytt@lan-login1 ~]% oxs S-2250220 'sh ver' 12 | Jan 29 2010 12:18:24 13 | K.14.54 14 | 79 15 | [fisakytt@lan-login1 ~]% cat > cmds 16 | show ip route 17 | [fisakytt@lan-login1 ~]% oxs -x cmds 62.236.123.199 18 | Default gateway is 62.236.123.198 19 | 20 | Host Gateway Last Use Total Uses Interface 21 | ICMP redirect cache is empty 22 | [fisakytt@lan-login1 ~]% cat >> cmds 23 | sh ip cef 24 | [fisakytt@lan-login1 ~]% cat cmds|oxs -x- 62.236.123.199 25 | Default gateway is 62.236.123.198 26 | 27 | Host Gateway Last Use Total Uses Interface 28 | ICMP redirect cache is empty 29 | %IPv4 CEF not running 30 | 31 | [nertwork@lan-login2 ~]% oxs --verbose --group ios --threads 4 --regex ^test 'show vrf' 32 | running list for hosts in group: ios and matching: ^test 33 | ## HOST - test-node-1 34 | ## OXS - show vrf 35 | Name Default RD Protocols Interfaces 36 | mgmtVRF ipv4,ipv6 Fa1 37 | 38 | [fisakytt@lan-login1 ~]% oxs --help 39 | Usage: oxs [options] hostname [command] 40 | -m, --model host model (ios, junos, etc), otherwise discovered from Oxidized source 41 | -o, --ostype OS Type (ios, junos, etc) 42 | -x, --commands commands file to be sent 43 | -u, --username username to use 44 | -p, --password password to use 45 | -t, --timeout timeout value to use 46 | -e, --enable enable password to use 47 | -c, --community snmp community to use for discovery 48 | -g, --group group to run commands on (ios, junos, etc), specified in oxidized db 49 | -r, --threads specify ammount of threads to use for running group (default: 1) 50 | --regex run on all hosts that match the regexp 51 | --dryrun do a dry run on either groups or regexp to find matching hosts 52 | --protocols protocols to use, default "ssh, telnet" 53 | -v, --verbose verbose output, e.g. show commands sent 54 | -d, --debug turn on debugging 55 | --terse display clean output 56 | --list-models list supported models 57 | --list-nodes list nodes in oxidized source 58 | -h, --help Display this help message. 59 | [fisakytt@lan-login1 ~]% 60 | 61 | 62 | ``` 63 | 64 | ### Library 65 | ``` 66 | [fisakytt@lan-login1 ~]% cat moi42.b 67 | #!/usr/bin/env ruby 68 | 69 | require 'oxidized/script' 70 | 71 | Oxidized::Config.load 72 | 73 | Oxidized::Script.new(:host=>'62.236.123.199') do |oxs| 74 | puts oxs.cmd 'show mac address-table dynamic vlan 101' 75 | end 76 | [fisakytt@lan-login1 ~]% ./moi42.b 77 | Mac Address Table 78 | ------------------------------------------- 79 | 80 | Vlan Mac Address Type Ports 81 | ---- ----------- -------- ----- 82 | 101 44d3.ca4c.383e DYNAMIC Gi0/1 83 | [fisakytt@lan-login1 ~]% 84 | ``` 85 | 86 | ## TODO 87 | * Interactive use? 88 | * Tests+docs, as always :( 89 | -------------------------------------------------------------------------------- /lib/oxidized/script/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | module Oxidized 4 | require 'oxidized' 5 | require_relative 'command' 6 | class Script 7 | attr_reader :model 8 | 9 | class ScriptError < OxidizedError; end 10 | class NoNode < ScriptError; end 11 | class InvalidOption < ScriptError; end 12 | class NoConnection < ScriptError 13 | attr_accessor :node_error 14 | end 15 | 16 | 17 | # @param [String] command command to be sent 18 | # @return [String] output for command 19 | def cmd command 20 | out = '' 21 | out += "## HOST - #{@host}\n" if @verbose 22 | out += "## OXS - #{command}\n" if @verbose 23 | cmd_out = @model.cmd command 24 | out += cmd_out if cmd_out 25 | out 26 | end 27 | 28 | # disconnects from ssh/telnet session 29 | # @return [void] 30 | def disconnect 31 | @input.disconnect_cli 32 | end 33 | alias_method :close, :disconnect 34 | 35 | private 36 | 37 | # @param [Hash] opts options for Oxidized::Script 38 | # @option opts [String] :host @hostname or ip address for Oxidized::Node 39 | # @option opts [String] :model node model (ios, junos etc) if defined, nodes are not loaded from source 40 | # @option opts [String] :ostype OS Type (ios, junos, etc) 41 | # @option opts [Fixnum] :timeout oxidized timeout 42 | # @option opts [String] :username username for login 43 | # @option opts [String] :passsword password for login 44 | # @option opts [String] :enable enable password to use 45 | # @option opts [String] :community community to use for discovery 46 | # @option opts [String] :protocols protocols to use to connect, default "ssh ,telnet" 47 | # @option opts [boolean] :verbose extra output, e.g. show command given in output 48 | # @yieldreturn [self] if called in block, returns self and disconnnects session after exiting block 49 | # @return [void] 50 | def initialize opts, &block 51 | @host = opts.delete :host 52 | model = opts.delete :model 53 | ostype = opts.delete :ostype 54 | timeout = opts.delete :timeout 55 | username = opts.delete :username 56 | password = opts.delete :password 57 | enable = opts.delete :enable 58 | community = opts.delete :community 59 | group = opts.delete :group 60 | @verbose = opts.delete :verbose 61 | Oxidized.config.input.default = opts.delete :protocols if opts[:protocols] 62 | raise InvalidOption, "#{opts} not recognized" unless opts.empty? 63 | 64 | @@oxi ||= false 65 | if not @@oxi 66 | Oxidized.mgr = Manager.new 67 | @@oxi = true 68 | end 69 | 70 | @node = if model 71 | Node.new(:name=>@host, :model=>model) 72 | else 73 | Nodes.new(:node=>@host).first 74 | end 75 | if not @node 76 | begin 77 | require 'corona' 78 | community ||= Corona::CFG.community 79 | rescue LoadError 80 | raise NoNode, 'node not found' 81 | end 82 | node = Corona.poll :host=>@host, :community=>community 83 | raise NoNode, 'node not found' unless node 84 | @node = Node.new :name=>@host, :model=>node[:model] 85 | end 86 | @node.auth[:username] = username if username 87 | @node.auth[:password] = password if password 88 | Oxidized.config.vars.enable = enable if enable 89 | Oxidized.config.timeout = timeout if timeout 90 | @model = @node.model 91 | @input = nil 92 | connect 93 | if block_given? 94 | yield self 95 | disconnect 96 | end 97 | end 98 | 99 | def connect 100 | node_error = {} 101 | @node.input.each do |input| 102 | begin 103 | @node.model.input = input.new 104 | @node.model.input.connect @node 105 | break 106 | rescue => error 107 | node_error[input] = error 108 | end 109 | end 110 | @input = @node.model.input 111 | err = NoConnection.new 112 | err.node_error = node_error 113 | raise err, 'unable to connect' unless @input.connected? 114 | @input.connect_cli 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/oxidized/script/cli.rb: -------------------------------------------------------------------------------- 1 | module Oxidized 2 | require_relative 'script' 3 | require 'slop' 4 | 5 | class Script 6 | class CLI 7 | attr_accessor :cmd_class 8 | class CLIError < ScriptError; end 9 | class NothingToDo < ScriptError; end 10 | 11 | def run 12 | if @group or @regex or @ostype 13 | $stdout.sync = true 14 | nodes = get_hosts 15 | counter = @threads.to_i 16 | Signal.trap("CLD") { counter += 1 } 17 | nodes.each do |node| 18 | Process.wait if counter <= 0 19 | puts "Forking " + node if @verbose 20 | counter -= 1 21 | fork { 22 | begin 23 | @host = node 24 | connect 25 | if @opts[:commands] 26 | puts "Running commands on #{node}:\n#{run_file @opts[:commands]}" 27 | elsif @cmd 28 | puts "Running commands on #{node}:\n#{@oxs.cmd @cmd}" 29 | end 30 | rescue => error 31 | puts "We had the following error on node #{node}:\n#{error}" 32 | end 33 | } 34 | end 35 | Process.waitall 36 | else 37 | connect 38 | if @opts[:commands] 39 | puts run_file @opts[:commands] 40 | elsif @cmd 41 | puts @oxs.cmd @cmd 42 | end 43 | end 44 | end 45 | 46 | private 47 | 48 | def initialize 49 | @args, @opts = opts_parse load_dynamic 50 | 51 | Config.load(@opts) 52 | 53 | if @opts[:commands] 54 | Oxidized.config.vars.ssh_no_exec = true 55 | end 56 | 57 | if @cmd_class 58 | @cmd_class.run :args=>@args, :opts=>@opts, :host=>@host, :cmd=>@cmd 59 | exit 0 60 | else 61 | if @group or @regex or @ostype 62 | @cmd = @args.shift 63 | else 64 | @host = @args.shift 65 | @cmd = @args.shift if @args 66 | end 67 | @oxs = nil 68 | raise NothingToDo, 'no host given' if not @host and not @group and not @ostype and not @regex 69 | if @dryrun 70 | puts get_hosts 71 | exit 72 | end 73 | raise NothingToDo, 'nothing to do, give command or -x' if not @cmd and not @opts[:commands] 74 | raise NothingToDo, 'nothing to do, no hosts matched' if get_hosts.empty? 75 | end 76 | end 77 | 78 | def opts_parse cmds 79 | opts = Slop.parse do |opt| 80 | opt.banner = 'Usage: oxs [options] hostname [command]' 81 | opt.on '-h', '--help', 'show usage' do 82 | puts opt 83 | exit 84 | end 85 | opt.string '-m', '--model', 'host model (ios, junos, etc), otherwise discovered from Oxidized source' 86 | opt.string '-o', '--ostype', 'OS Type (ios, junos, etc)' 87 | opt.string '-x', '--commands', 'commands file to be sent' 88 | opt.string '-u', '--username', 'username to use' 89 | opt.string '-p', '--password', 'password to use' 90 | opt.int '-t', '--timeout', 'timeout value to use' 91 | opt.string '-e', '--enable', 'enable password to use' 92 | opt.string '-c', '--community', 'snmp community to use for discovery' 93 | opt.string '-g', '--group', 'group to run commands on (ios, junos, etc), specified in oxidized db' 94 | opt.int '-r', '--threads', 'specify ammount of threads to use for running group', default: '1' 95 | opt.string '--regex', 'run on all hosts that match the regexp' 96 | opt.on '--dryrun', 'do a dry run on either groups or regexp to find matching hosts' 97 | opt.string '--protocols','protocols to use, default "ssh, telnet"' 98 | opt.on '--no-trim', 'Dont trim newlines and whitespace when running commands' 99 | opt.on '-v', '--verbose', 'verbose output, e.g. show commands sent' 100 | opt.on '-d', '--debug', 'turn on debugging' 101 | opt.on :terse, 'display clean output' 102 | 103 | cmds.each do |cmd| 104 | if cmd[:class].respond_to? :cmdline 105 | cmd[:class].cmdline opt, self 106 | else 107 | opt.on "--" + cmd[:name], cmd[:description] do 108 | @cmd_class = cmd[:class] 109 | end 110 | end 111 | end 112 | end 113 | @group = opts[:group] 114 | @ostype = opts[:ostype] 115 | @threads = opts[:threads] 116 | @verbose = opts[:verbose] 117 | @dryrun = opts[:dryrun] 118 | @regex = opts[:regex] 119 | [opts.arguments, opts] 120 | end 121 | 122 | def connect 123 | opts = {} 124 | opts[:host] = @host 125 | [:model, :username, :password, :timeout, :enable, :verbose, :community, :protocols].each do |key| 126 | opts[key] = @opts[key] if @opts[key] 127 | end 128 | @oxs = Script.new opts 129 | end 130 | 131 | def run_file file 132 | out = '' 133 | file = file == '-' ? $stdin : File.read(file) 134 | file.each_line do |line| 135 | # line.sub!(/\\n/, "\n") # treat escaped newline as newline 136 | line.chomp! unless @opts["no-trim"] 137 | out += @oxs.cmd line 138 | end 139 | out 140 | end 141 | 142 | def load_dynamic 143 | cmds = [] 144 | files = File.dirname __FILE__ 145 | files = File.join files, 'commands', '*.rb' 146 | files = Dir.glob files 147 | files.each { |file| require_relative file } 148 | Script::Command.constants.each do |cmd| 149 | next if cmd == :Base 150 | cmd = Script::Command.const_get cmd 151 | name = cmd.const_get :Name 152 | desc = cmd.const_get :Description 153 | cmds << { class: cmd, name: name, description: desc } 154 | end 155 | cmds 156 | end 157 | 158 | def get_hosts 159 | puts "running list for hosts" if @verbose 160 | if @group 161 | puts " - in group: #{@group}" if @verbose 162 | end 163 | if @ostype 164 | puts " - (and) matching ostype: #{@ostype}" if @verbose 165 | end 166 | if @regex 167 | puts " - (and) matching: #{@regex}" if @verbose 168 | end 169 | Oxidized.mgr = Manager.new 170 | out = [] 171 | loop_verbose = false # turn on/off verbose output for the following loop 172 | Nodes.new.each do |node| 173 | if @group 174 | puts " ... checking if #{node.name} in group: #{@group}, node group is: #{node.group}" if loop_verbose 175 | next unless @group == node.group 176 | end 177 | if @ostype 178 | puts " ... checking if #{node.name} matching ostype: #{@ostype}, node ostype is: #{node.model.to_s}" if loop_verbose 179 | next unless node.model.to_s.match(/#{@ostype}/i) 180 | end 181 | if @regex 182 | puts " ... checking if if #{node.name} matching: #{@regex}" if loop_verbose 183 | next unless node.name.match(/#{@regex}/) 184 | end 185 | out << node.name 186 | end 187 | out 188 | end 189 | 190 | end 191 | end 192 | end 193 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config --exclude-limit 10000` 3 | # on 2025-01-20 18:20:44 UTC using RuboCop version 1.70.0. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 1 10 | # Configuration parameters: Severity, Include. 11 | # Include: **/*.gemspec 12 | Gemspec/RequiredRubyVersion: 13 | Exclude: 14 | - 'oxidized-script.gemspec' 15 | 16 | # Offense count: 5 17 | # This cop supports safe autocorrection (--autocorrect). 18 | Layout/EmptyLineAfterGuardClause: 19 | Exclude: 20 | - 'lib/oxidized/script/cli.rb' 21 | - 'lib/oxidized/script/commands/list-nodes.rb' 22 | - 'lib/oxidized/script/script.rb' 23 | 24 | # Offense count: 2 25 | # This cop supports safe autocorrection (--autocorrect). 26 | # Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, DefLikeMacros, AllowAdjacentOneLineDefs, NumberOfEmptyLines. 27 | Layout/EmptyLineBetweenDefs: 28 | Exclude: 29 | - 'lib/oxidized/script/script.rb' 30 | 31 | # Offense count: 1 32 | # This cop supports safe autocorrection (--autocorrect). 33 | Layout/EmptyLines: 34 | Exclude: 35 | - 'lib/oxidized/script/script.rb' 36 | 37 | # Offense count: 1 38 | # This cop supports safe autocorrection (--autocorrect). 39 | # Configuration parameters: AllowAliasSyntax, AllowedMethods. 40 | # AllowedMethods: alias_method, public, protected, private 41 | Layout/EmptyLinesAroundAttributeAccessor: 42 | Exclude: 43 | - 'lib/oxidized/script/cli.rb' 44 | 45 | # Offense count: 3 46 | # This cop supports safe autocorrection (--autocorrect). 47 | # Configuration parameters: EnforcedStyle. 48 | # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only 49 | Layout/EmptyLinesAroundClassBody: 50 | Exclude: 51 | - 'lib/oxidized/script/cli.rb' 52 | - 'lib/oxidized/script/commands/list-models.rb' 53 | - 'lib/oxidized/script/commands/list-nodes.rb' 54 | 55 | # Offense count: 11 56 | # This cop supports safe autocorrection (--autocorrect). 57 | # Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment. 58 | Layout/ExtraSpacing: 59 | Exclude: 60 | - 'lib/oxidized/script/cli.rb' 61 | - 'lib/oxidized/script/commands/list-nodes.rb' 62 | 63 | # Offense count: 1 64 | # This cop supports safe autocorrection (--autocorrect). 65 | Layout/SpaceAfterComma: 66 | Exclude: 67 | - 'lib/oxidized/script/cli.rb' 68 | 69 | # Offense count: 4 70 | # This cop supports safe autocorrection (--autocorrect). 71 | # Configuration parameters: . 72 | # SupportedStyles: space, no_space 73 | Layout/SpaceAroundEqualsInParameterDefault: 74 | EnforcedStyle: no_space 75 | 76 | # Offense count: 12 77 | # This cop supports safe autocorrection (--autocorrect). 78 | # Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator, EnforcedStyleForRationalLiterals. 79 | # SupportedStylesForExponentOperator: space, no_space 80 | # SupportedStylesForRationalLiterals: space, no_space 81 | Layout/SpaceAroundOperators: 82 | Exclude: 83 | - 'lib/oxidized/script/cli.rb' 84 | - 'lib/oxidized/script/script.rb' 85 | 86 | # Offense count: 4 87 | # This cop supports safe autocorrection (--autocorrect). 88 | # Configuration parameters: AllowForAlignment. 89 | Layout/SpaceBeforeFirstArg: 90 | Exclude: 91 | - 'lib/oxidized/script/cli.rb' 92 | 93 | # Offense count: 2 94 | # Configuration parameters: AllowedParentClasses. 95 | Lint/MissingSuper: 96 | Exclude: 97 | - 'lib/oxidized/script/commands/list-models.rb' 98 | - 'lib/oxidized/script/commands/list-nodes.rb' 99 | 100 | # Offense count: 1 101 | # This cop supports safe autocorrection (--autocorrect). 102 | Lint/RedundantStringCoercion: 103 | Exclude: 104 | - 'lib/oxidized/script/cli.rb' 105 | 106 | # Offense count: 1 107 | # This cop supports safe autocorrection (--autocorrect). 108 | Lint/ScriptPermission: 109 | Exclude: 110 | - 'lib/oxidized/script/script.rb' 111 | 112 | # Offense count: 2 113 | # This cop supports safe autocorrection (--autocorrect). 114 | # Configuration parameters: AutoCorrect, AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions. 115 | # NotImplementedExceptions: NotImplementedError 116 | Lint/UnusedMethodArgument: 117 | Exclude: 118 | - 'lib/oxidized/script/commands/list-nodes.rb' 119 | - 'lib/oxidized/script/script.rb' 120 | 121 | # Offense count: 2 122 | # This cop supports safe autocorrection (--autocorrect). 123 | # Configuration parameters: AutoCorrect. 124 | Lint/UselessAssignment: 125 | Exclude: 126 | - 'lib/oxidized/script/script.rb' 127 | 128 | # Offense count: 6 129 | # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. 130 | Metrics/AbcSize: 131 | Max: 54 132 | 133 | # Offense count: 1 134 | # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. 135 | # AllowedMethods: refine 136 | Metrics/BlockLength: 137 | Max: 31 138 | 139 | # Offense count: 1 140 | # Configuration parameters: CountComments, CountAsOne. 141 | Metrics/ClassLength: 142 | Max: 168 143 | 144 | # Offense count: 4 145 | # Configuration parameters: AllowedMethods, AllowedPatterns. 146 | Metrics/CyclomaticComplexity: 147 | Max: 18 148 | 149 | # Offense count: 8 150 | # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. 151 | Metrics/MethodLength: 152 | Max: 44 153 | 154 | # Offense count: 4 155 | # Configuration parameters: AllowedMethods, AllowedPatterns. 156 | Metrics/PerceivedComplexity: 157 | Max: 18 158 | 159 | # Offense count: 1 160 | Naming/AccessorMethodName: 161 | Exclude: 162 | - 'lib/oxidized/script/cli.rb' 163 | 164 | # Offense count: 4 165 | Naming/ConstantName: 166 | Exclude: 167 | - 'lib/oxidized/script/commands/list-models.rb' 168 | - 'lib/oxidized/script/commands/list-nodes.rb' 169 | 170 | # Offense count: 2 171 | # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms. 172 | # CheckDefinitionPathHierarchyRoots: lib, spec, test, src 173 | # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS 174 | Naming/FileName: 175 | Exclude: 176 | - 'Rakefile.rb' 177 | - 'lib/oxidized/script/commands/list-models.rb' 178 | - 'lib/oxidized/script/commands/list-nodes.rb' 179 | 180 | # Offense count: 3 181 | # This cop supports safe autocorrection (--autocorrect). 182 | # Configuration parameters: PreferredName. 183 | Naming/RescuedExceptionsVariableName: 184 | Exclude: 185 | - 'bin/oxs' 186 | - 'lib/oxidized/script/cli.rb' 187 | - 'lib/oxidized/script/script.rb' 188 | 189 | # Offense count: 1 190 | Security/Eval: 191 | Exclude: 192 | - 'Rakefile' 193 | 194 | # Offense count: 1 195 | # This cop supports safe autocorrection (--autocorrect). 196 | # Configuration parameters: EnforcedStyle. 197 | # SupportedStyles: prefer_alias, prefer_alias_method 198 | Style/Alias: 199 | Exclude: 200 | - 'lib/oxidized/script/script.rb' 201 | 202 | # Offense count: 8 203 | # This cop supports unsafe autocorrection (--autocorrect-all). 204 | # Configuration parameters: EnforcedStyle. 205 | # SupportedStyles: always, conditionals 206 | Style/AndOr: 207 | Exclude: 208 | - 'lib/oxidized/script/cli.rb' 209 | 210 | # Offense count: 1 211 | # This cop supports safe autocorrection (--autocorrect). 212 | # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods. 213 | # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces 214 | # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object 215 | # FunctionalMethods: let, let!, subject, watch 216 | # AllowedMethods: lambda, proc, it 217 | Style/BlockDelimiters: 218 | Exclude: 219 | - 'lib/oxidized/script/cli.rb' 220 | 221 | # Offense count: 2 222 | Style/ClassVars: 223 | Exclude: 224 | - 'lib/oxidized/script/script.rb' 225 | 226 | # Offense count: 1 227 | # This cop supports safe autocorrection (--autocorrect). 228 | # Configuration parameters: EnforcedStyle, AllowInnerBackticks. 229 | # SupportedStyles: backticks, percent_x, mixed 230 | Style/CommandLiteral: 231 | Exclude: 232 | - 'Rakefile' 233 | 234 | # Offense count: 7 235 | # Configuration parameters: AllowedConstants. 236 | Style/Documentation: 237 | Exclude: 238 | - 'spec/**/*' 239 | - 'test/**/*' 240 | - 'lib/oxidized/script/cli.rb' 241 | - 'lib/oxidized/script/commands/list-models.rb' 242 | - 'lib/oxidized/script/commands/list-nodes.rb' 243 | - 'lib/oxidized/script/script.rb' 244 | 245 | # Offense count: 1 246 | # This cop supports safe autocorrection (--autocorrect). 247 | # Configuration parameters: AutoCorrect, EnforcedStyle. 248 | # SupportedStyles: compact, expanded 249 | Style/EmptyMethod: 250 | Exclude: 251 | - 'lib/oxidized/script/commands/list-models.rb' 252 | 253 | # Offense count: 2 254 | # This cop supports safe autocorrection (--autocorrect). 255 | # Configuration parameters: EnforcedStyle. 256 | # SupportedStyles: format, sprintf, percent 257 | Style/FormatString: 258 | Exclude: 259 | - 'lib/oxidized/script/commands/list-models.rb' 260 | - 'lib/oxidized/script/commands/list-nodes.rb' 261 | 262 | # Offense count: 4 263 | # This cop supports safe autocorrection (--autocorrect). 264 | # Configuration parameters: MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns. 265 | # SupportedStyles: annotated, template, unannotated 266 | Style/FormatStringToken: 267 | EnforcedStyle: unannotated 268 | 269 | # Offense count: 10 270 | # This cop supports unsafe autocorrection (--autocorrect-all). 271 | # Configuration parameters: EnforcedStyle. 272 | # SupportedStyles: always, always_true, never 273 | Style/FrozenStringLiteralComment: 274 | Exclude: 275 | - 'Gemfile' 276 | - 'Rakefile' 277 | - 'bin/oxs' 278 | - 'lib/oxidized/script.rb' 279 | - 'lib/oxidized/script/cli.rb' 280 | - 'lib/oxidized/script/command.rb' 281 | - 'lib/oxidized/script/commands/list-models.rb' 282 | - 'lib/oxidized/script/commands/list-nodes.rb' 283 | - 'lib/oxidized/script/script.rb' 284 | - 'oxidized-script.gemspec' 285 | 286 | # Offense count: 1 287 | # This cop supports safe autocorrection (--autocorrect). 288 | # Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. 289 | Style/GuardClause: 290 | Exclude: 291 | - 'lib/oxidized/script/script.rb' 292 | 293 | # Offense count: 11 294 | # This cop supports safe autocorrection (--autocorrect). 295 | # Configuration parameters: EnforcedStyle, EnforcedShorthandSyntax, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. 296 | # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys 297 | # SupportedShorthandSyntax: always, never, either, consistent, either_consistent 298 | Style/HashSyntax: 299 | Exclude: 300 | - 'lib/oxidized/script/cli.rb' 301 | - 'lib/oxidized/script/script.rb' 302 | 303 | # Offense count: 1 304 | # This cop supports safe autocorrection (--autocorrect). 305 | Style/IfUnlessModifier: 306 | Exclude: 307 | - 'lib/oxidized/script/cli.rb' 308 | 309 | # Offense count: 9 310 | # This cop supports safe autocorrection (--autocorrect). 311 | # Configuration parameters: EnforcedStyle. 312 | # SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline 313 | Style/MethodDefParentheses: 314 | Exclude: 315 | - 'lib/oxidized/script/cli.rb' 316 | - 'lib/oxidized/script/commands/list-models.rb' 317 | - 'lib/oxidized/script/commands/list-nodes.rb' 318 | - 'lib/oxidized/script/script.rb' 319 | 320 | # Offense count: 4 321 | # This cop supports unsafe autocorrection (--autocorrect-all). 322 | # Configuration parameters: EnforcedStyle. 323 | # SupportedStyles: literals, strict 324 | Style/MutableConstant: 325 | Exclude: 326 | - 'lib/oxidized/script/commands/list-models.rb' 327 | - 'lib/oxidized/script/commands/list-nodes.rb' 328 | 329 | # Offense count: 2 330 | # This cop supports safe autocorrection (--autocorrect). 331 | # Configuration parameters: EnforcedStyle. 332 | # SupportedStyles: both, prefix, postfix 333 | Style/NegatedIf: 334 | Exclude: 335 | - 'lib/oxidized/script/script.rb' 336 | 337 | # Offense count: 8 338 | # This cop supports safe autocorrection (--autocorrect). 339 | Style/Not: 340 | Exclude: 341 | - 'lib/oxidized/script/cli.rb' 342 | - 'lib/oxidized/script/script.rb' 343 | 344 | # Offense count: 1 345 | # This cop supports safe autocorrection (--autocorrect). 346 | Style/RedundantBegin: 347 | Exclude: 348 | - 'lib/oxidized/script/script.rb' 349 | 350 | # Offense count: 1 351 | # This cop supports unsafe autocorrection (--autocorrect-all). 352 | Style/RedundantInterpolation: 353 | Exclude: 354 | - 'bin/oxs' 355 | 356 | # Offense count: 3 357 | # This cop supports safe autocorrection (--autocorrect). 358 | # Configuration parameters: EnforcedStyle. 359 | # SupportedStyles: implicit, explicit 360 | Style/RescueStandardError: 361 | Exclude: 362 | - 'bin/oxs' 363 | - 'lib/oxidized/script/cli.rb' 364 | - 'lib/oxidized/script/script.rb' 365 | 366 | # Offense count: 1 367 | # This cop supports unsafe autocorrection (--autocorrect-all). 368 | Style/SlicingWithRange: 369 | Exclude: 370 | - 'lib/oxidized/script/commands/list-nodes.rb' 371 | 372 | # Offense count: 3 373 | # This cop supports safe autocorrection (--autocorrect). 374 | # Configuration parameters: AllowModifier. 375 | Style/SoleNestedConditional: 376 | Exclude: 377 | - 'lib/oxidized/script/cli.rb' 378 | 379 | # Offense count: 3 380 | # This cop supports unsafe autocorrection (--autocorrect-all). 381 | # Configuration parameters: Mode. 382 | Style/StringConcatenation: 383 | Exclude: 384 | - 'Rakefile' 385 | - 'lib/oxidized/script/cli.rb' 386 | 387 | # Offense count: 5 388 | # This cop supports safe autocorrection (--autocorrect). 389 | # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. 390 | # SupportedStyles: single_quotes, double_quotes 391 | Style/StringLiterals: 392 | Exclude: 393 | - 'lib/oxidized/script/cli.rb' 394 | 395 | # Offense count: 1 396 | # This cop supports safe autocorrection (--autocorrect). 397 | # Configuration parameters: MinSize. 398 | # SupportedStyles: percent, brackets 399 | Style/SymbolArray: 400 | EnforcedStyle: brackets 401 | 402 | # Offense count: 1 403 | # This cop supports safe autocorrection (--autocorrect). 404 | # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings. 405 | # URISchemes: http, https 406 | Layout/LineLength: 407 | Max: 128 408 | --------------------------------------------------------------------------------