From e2cf8d760429700d6d3387e19577d3fd93c6940a Mon Sep 17 00:00:00 2001 From: John Corbin Date: Mon, 21 Mar 2016 21:20:46 -0700 Subject: [PATCH 01/60] Created vlans set_trunk_groups method. --- lib/rbeapi/api/vlans.rb | 44 +++++++++++++++++++++ spec/system/rbeapi/api/vlans_spec.rb | 46 ++++++++++++++++++++++ spec/unit/rbeapi/api/vlans/default_spec.rb | 30 ++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/lib/rbeapi/api/vlans.rb b/lib/rbeapi/api/vlans.rb index 561bcea..3760f8a 100644 --- a/lib/rbeapi/api/vlans.rb +++ b/lib/rbeapi/api/vlans.rb @@ -333,6 +333,50 @@ def add_trunk_group(id, value) def remove_trunk_group(id, value) configure(["vlan #{id}", "no trunk group #{value}"]) end + + ## + # Configures the trunk groups for the specified vlan. + # Trunk groups not currently set are added and trunk groups + # currently configured but not in the passed in value array are removed. + # + # @param name [String] The name of the vlan to configure. + # + # @param opts [Hash] The configuration parameters for the vlan. + # + # @option opts value [string] Set of values to configure the trunk group. + # + # @option opts enable [Boolean] If false then the command is + # negated. Default is true. + # + # @option opts default [Boolean] The value should be set to default + # Default takes precedence over enable. + # + # @return [Boolean] Returns True if the commands succeed otherwise False. + def set_trunk_groups(name, opts = {}) + default = opts.fetch(:default, false) + return configure(["vlan #{name}", 'default trunk group']) if default + + enable = opts.fetch(:enable, true) + return configure(["vlan #{name}", 'no trunk group']) unless enable + + value = opts.fetch(:value, []) + fail ArgumentError, 'value must be an Array' unless value.is_a?(Array) + + value = Set.new value + current_value = Set.new get(name)[:trunk_groups] + + cmds = ["vlan #{name}"] + # Add trunk groups that are not currently in the list. + value.difference(current_value).each do |group| + cmds << "trunk group #{group}" + end + + # Remove trunk groups that are not in the new list. + current_value.difference(value).each do |group| + cmds << "no trunk group #{group}" + end + configure(cmds) if cmds.length > 1 + end end end end diff --git a/spec/system/rbeapi/api/vlans_spec.rb b/spec/system/rbeapi/api/vlans_spec.rb index fe0692f..a75a68a 100644 --- a/spec/system/rbeapi/api/vlans_spec.rb +++ b/spec/system/rbeapi/api/vlans_spec.rb @@ -159,4 +159,50 @@ expect(subject.get('1')[:trunk_groups]).not_to include('foo') end end + + describe '#set_trunk_groups' do + before do + node.config(['vlan 1', 'default trunk group']) + end + + it 'raises an ArgumentError if value is not an array' do + expect { subject.set_trunk_groups('1', value: 'foo') } + .to raise_error(ArgumentError) + end + + it 'sets trunk group to foo bar bang' do + node.config(['vlan 1', 'trunk group bang', 'trunk group baz']) + expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz)) + expect(subject.set_trunk_groups('1', value: %w(foo bar bang))) + .to be_truthy + expect(subject.get('1')[:trunk_groups].sort).to eq(%w(bang bar foo)) + end + + it 'clears trunk group if no value specified' do + node.config(['vlan 1', 'trunk group bang', 'trunk group baz']) + expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz)) + expect(subject.set_trunk_groups('1')).to be_truthy + expect(subject.get('1')[:trunk_groups]).to be_empty + end + + it 'negate trunk group' do + node.config(['vlan 1', 'trunk group bang', 'trunk group baz']) + expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz)) + expect(subject.set_trunk_groups('1', value: %w(foo bar bang))) + .to be_truthy + expect(subject.get('1')[:trunk_groups].sort).to eq(%w(bang bar foo)) + expect(subject.set_trunk_groups('1', enable: false)).to be_truthy + expect(subject.get('1')[:trunk_groups]).to be_empty + end + + it 'default trunk group' do + node.config(['vlan 1', 'trunk group bang', 'trunk group baz']) + expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz)) + expect(subject.set_trunk_groups('1', value: %w(foo bar bang))) + .to be_truthy + expect(subject.get('1')[:trunk_groups].sort).to eq(%w(bang bar foo)) + expect(subject.set_trunk_groups('1', default: true)).to be_truthy + expect(subject.get('1')[:trunk_groups]).to be_empty + end + end end diff --git a/spec/unit/rbeapi/api/vlans/default_spec.rb b/spec/unit/rbeapi/api/vlans/default_spec.rb index 09f48c5..3e1920d 100644 --- a/spec/unit/rbeapi/api/vlans/default_spec.rb +++ b/spec/unit/rbeapi/api/vlans/default_spec.rb @@ -132,4 +132,34 @@ def vlans expect(subject.remove_trunk_group('1', 'foo')).to be_truthy end end + + describe '#set_trunk_groups' do + it 'raises an ArgumentError if value is not an array' do + expect { subject.set_trunk_groups('vlan 1', value: 'foo') } + .to raise_error(ArgumentError) + end + + it 'sets trunk group to foo bar bang' do + expect(node).to receive(:config) + .with(['vlan 1', 'trunk group foo', + 'trunk group bar', 'trunk group bang', 'no trunk group mlag_ctl', + 'no trunk group test']) + expect(subject.set_trunk_groups('1', value: %w(foo bar bang))) + .to be_truthy + end + + it 'negate switchport trunk group' do + expect(node).to receive(:config) + .with(['vlan 1', 'no trunk group']) + expect(subject.set_trunk_groups('1', enable: false)) + .to be_truthy + end + + it 'default switchport trunk group' do + expect(node).to receive(:config) + .with(['vlan 1', 'default trunk group']) + expect(subject.set_trunk_groups('1', default: true)) + .to be_truthy + end + end end From e96b87e12afafc112ce1c18f613e93615e63cbeb Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 6 Apr 2016 10:00:36 -0400 Subject: [PATCH 02/60] Ignore local changes to dut.conf --- spec/fixtures/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 spec/fixtures/.gitignore diff --git a/spec/fixtures/.gitignore b/spec/fixtures/.gitignore new file mode 100644 index 0000000..456ba3f --- /dev/null +++ b/spec/fixtures/.gitignore @@ -0,0 +1 @@ +dut.conf From fe3bc8078020e39e115025fd7dca17bcf9b3c8be Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 6 Apr 2016 10:07:19 -0400 Subject: [PATCH 03/60] Fixes #123 --- lib/rbeapi/api/system.rb | 2 +- spec/unit/rbeapi/api/system/default_spec.rb | 5 +++++ spec/unit/rbeapi/api/system/fixture_system.text | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/api/system.rb b/lib/rbeapi/api/system.rb index db775f4..92fb203 100644 --- a/lib/rbeapi/api/system.rb +++ b/lib/rbeapi/api/system.rb @@ -92,7 +92,7 @@ def parse_hostname(config) # # @return [Hash] The resource hash attribute. def parse_iprouting(config) - mdata = /no\sip\srouting/.match(config) + mdata = /no\sip\srouting$/.match(config) { iprouting: mdata.nil? ? true : false } end private :parse_iprouting diff --git a/spec/unit/rbeapi/api/system/default_spec.rb b/spec/unit/rbeapi/api/system/default_spec.rb index ef4e1fc..29b0910 100644 --- a/spec/unit/rbeapi/api/system/default_spec.rb +++ b/spec/unit/rbeapi/api/system/default_spec.rb @@ -68,6 +68,11 @@ def system it 'has four entries' do expect(subject.get.size).to eq(4) end + + it 'retrieves only global ip routing' do + expect(subject.get.size).to eq(4) + expect(subject.get[:iprouting]).to eq(true) + end end describe '#set_hostname' do diff --git a/spec/unit/rbeapi/api/system/fixture_system.text b/spec/unit/rbeapi/api/system/fixture_system.text index df8459d..8ea0d5f 100644 --- a/spec/unit/rbeapi/api/system/fixture_system.text +++ b/spec/unit/rbeapi/api/system/fixture_system.text @@ -1,5 +1,6 @@ hostname localhost ip routing +no ip routing vrf foo banner login Login Banner Second Line From 5285ab45883ca25189f1774c412c7915eb020cf9 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 6 Apr 2016 16:20:14 -0400 Subject: [PATCH 04/60] Fix #118 and bypass docs on install --- gems/net_http_unix/net_http_unix.spec.tmpl | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gems/net_http_unix/net_http_unix.spec.tmpl b/gems/net_http_unix/net_http_unix.spec.tmpl index 1c97b26..a8a7d90 100644 --- a/gems/net_http_unix/net_http_unix.spec.tmpl +++ b/gems/net_http_unix/net_http_unix.spec.tmpl @@ -3,7 +3,7 @@ Name: %{?enterprise:pe-}rubygem-%{gem_name} Version: 0.2.1 -Release: 3.eos4 +Release: 4.eos4 Summary: Wrapper around Net::HTTP with AF_UNIX support Group: Development/Languages @@ -52,7 +52,7 @@ install %{SOURCE0} %{buildroot}/ /%{gem_name}-%{version}.gem %post -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun @@ -60,7 +60,7 @@ gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet3 GEM=/opt/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet3 @@ -69,14 +69,17 @@ ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet-aio GEM=/opt/puppetlabs/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet-aio GEM=/opt/puppetlabs/puppet/bin/gem -${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1pckage puppet3 +${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog +* Wed Apr 6 2016 Jere Julian - 0.2.1-4 +- Disable install of gem docs + * Fri Oct 30 2015 Jere Julian - 0.2.1-3 - Detect the location of the puppet-agent's gem install From ed2619d2e3a3c936024f0f593682700f2ad680b3 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 6 Apr 2016 16:20:48 -0400 Subject: [PATCH 05/60] Bypass docs on install --- gems/inifile/inifile.spec.tmpl | 11 +++++++---- gems/netaddr/netaddr.spec.tmpl | 11 +++++++---- rbeapi.spec.tmpl | 6 +++--- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/gems/inifile/inifile.spec.tmpl b/gems/inifile/inifile.spec.tmpl index 3df8a05..a49e932 100644 --- a/gems/inifile/inifile.spec.tmpl +++ b/gems/inifile/inifile.spec.tmpl @@ -3,7 +3,7 @@ Name: %{?enterprise:pe-}rubygem-%{gem_name} Version: 3.0.0 -Release: 3.eos4 +Release: 4.eos4 Summary: INI file reader and writer Group: Development/Languages @@ -85,7 +85,7 @@ install %{SOURCE0} %{buildroot}/ /%{gem_name}-%{version}.gem %post -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun @@ -93,7 +93,7 @@ gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet3 GEM=/opt/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet3 @@ -102,7 +102,7 @@ ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet-aio GEM=/opt/puppetlabs/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet-aio @@ -110,6 +110,9 @@ GEM=/opt/puppetlabs/puppet/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog +* Wed Apr 6 2016 Jere Julian - 3.0.0-4 +- Disable install of gem docs + * Fri Oct 30 2015 Jere Julian - 3.0.0-3 - Detect the location of the puppet-agent's gem install diff --git a/gems/netaddr/netaddr.spec.tmpl b/gems/netaddr/netaddr.spec.tmpl index cf1dee8..594ae1d 100644 --- a/gems/netaddr/netaddr.spec.tmpl +++ b/gems/netaddr/netaddr.spec.tmpl @@ -3,7 +3,7 @@ Name: %{?enterprise:pe-}rubygem-%{gem_name} Version: 1.5.0 -Release: 2.eos4 +Release: 3.eos4 Summary: A package for manipulating network addresses Group: Development/Languages License: Unknown @@ -51,7 +51,7 @@ install %{SOURCE0} %{buildroot}/ /%{gem_name}-%{version}.gem %post -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun @@ -59,7 +59,7 @@ gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet3 GEM=/opt/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet3 @@ -68,7 +68,7 @@ ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet-aio GEM=/opt/puppetlabs/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet-aio @@ -76,6 +76,9 @@ GEM=/opt/puppetlabs/puppet/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog +* Wed Apr 6 2016 Jere Julian - 1.5.0-3 +- Disable install of gem docs + * Fri Oct 30 2015 Jere Julian - 1.5.0-2 - Detect the location of the puppet-agent's gem install diff --git a/rbeapi.spec.tmpl b/rbeapi.spec.tmpl index a2faa07..d3d1840 100644 --- a/rbeapi.spec.tmpl +++ b/rbeapi.spec.tmpl @@ -73,7 +73,7 @@ install %{SOURCE0} %{buildroot}/ /%{gem_name}-%{version}.gem %post -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun @@ -81,7 +81,7 @@ gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet3 GEM=/opt/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet3 @@ -90,7 +90,7 @@ ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet-aio GEM=/opt/puppetlabs/puppet/bin/gem -GEM_OPTS="--no-document --local" +GEM_OPTS="--no-rdoc --no-ri --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun puppet-aio From 19dc097cb9c2543d3df67245013f9a5d326b38fa Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 6 Apr 2016 16:46:34 -0400 Subject: [PATCH 06/60] Update rpm versions and add bash parens for the swix target --- Rakefile | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Rakefile b/Rakefile index f41752a..9998faf 100644 --- a/Rakefile +++ b/Rakefile @@ -86,46 +86,48 @@ task all_rpms: :build do puts ' cd /mnt/flash; \\' puts " swix create rbeapi-#{Rbeapi::VERSION}-1.swix \\" puts " rubygem-rbeapi-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" - puts ' rubygem-inifile-3.0.0-3.eos4.noarch.rpm \\' - puts ' rubygem-netaddr-1.5.0-2.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-0.2.1-3.eos4.noarch.rpm' + puts ' rubygem-inifile-3.0.0-4.eos4.noarch.rpm \\' + puts ' rubygem-netaddr-1.5.1-3.eos4.noarch.rpm \\' + puts ' rubygem-net_http_unix-0.2.1-4.eos4.noarch.rpm' puts ' Puppet-enterprise agent (3.x): ' puts ' cd/mnt/flash; \\' puts " swix create rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix \\" puts " rubygem-rbeapi-puppet3-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" - puts ' rubygem-inifile-puppet3-3.0.0-3.eos4.noarch.rpm \\' - puts ' rubygem-netaddr-puppet3-1.5.0-2.eos4.noarch.rpm' + puts ' rubygem-inifile-puppet3-3.0.0-4.eos4.noarch.rpm \\' + puts ' rubygem-netaddr-puppet3-1.5.1-3.eos4.noarch.rpm' puts ' Puppet-All-in-one agent (2015.x/4.x): ' puts ' cd/mnt/flash; \\' puts " swix create rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.swix \\" puts " rubygem-rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" - puts ' rubygem-inifile-puppet-aio-3.0.0-3.eos4.noarch.rpm \\' - puts ' rubygem-netaddr-puppet-aio-1.5.0-2.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-puppet-aio-0.2.1-3.eos4.noarch.rpm' + puts ' rubygem-inifile-puppet-aio-3.0.0-4.eos4.noarch.rpm \\' + puts ' rubygem-netaddr-puppet-aio-1.5.1-3.eos4.noarch.rpm \\' + puts ' rubygem-net_http_unix-puppet-aio-0.2.1-4.eos4.noarch.rpm' end desc 'Generate SWIX files from RPMs' task swix: :all_rpms do SWIX = 'PYTHONPATH=${PYTHONPATH}:/nfs/misc/tools/swix \ /nfs/misc/tools/swix/swix' - system "cd rpms/noarch; + system "(cd rpms/noarch; rm -f rbeapi-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-#{Rbeapi::VERSION}-1.swix \ rubygem-rbeapi-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ - rubygem-inifile-3.0.0-3.eos4.noarch.rpm \ - rubygem-netaddr-1.5.0-2.eos4.noarch.rpm" - system "cd rpms/noarch; + rubygem-inifile-3.0.0-4.eos4.noarch.rpm \ + rubygem-netaddr-1.5.1-3.eos4.noarch.rpm \ + rubygem-net_http_unix-0.2.1-4.eos4.noarch.rpm)" + system "(cd rpms/noarch; rm -f rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix \ rubygem-rbeapi-puppet3-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ - rubygem-inifile-puppet3-3.0.0-3.eos4.noarch.rpm \ - rubygem-netaddr-puppet3-1.5.0-2.eos4.noarch.rpm" - system "cd rpms/noarch; + rubygem-inifile-puppet3-3.0.0-4.eos4.noarch.rpm \ + rubygem-netaddr-puppet3-1.5.1-3.eos4.noarch.rpm)" + system "(cd rpms/noarch; rm -f rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.swix \ rubygem-rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ - rubygem-inifile-puppet-aio-3.0.0-3.eos4.noarch.rpm \ - rubygem-netaddr-puppet-aio-1.5.0-2.eos4.noarch.rpm" + rubygem-inifile-puppet-aio-3.0.0-4.eos4.noarch.rpm \ + rubygem-netaddr-puppet-aio-1.5.1-3.eos4.noarch.rpm \ + rubygem-net_http_unix-puppet-aio-0.2.1-4.eos4.noarch.rpm)" SWIXS = `find rpms/noarch -name "rbeapi*swix" -ls` puts "\n################################################\n#" puts "The following artifacts are in rpms/noarch/\n#{SWIXS}" From a6ce6adb57e7362e1cc485396f28e25262b1e0ac Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 6 Apr 2016 17:01:08 -0400 Subject: [PATCH 07/60] Fix whitespace issue from rpmlint --- gems/net_http_unix/net_http_unix.spec.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gems/net_http_unix/net_http_unix.spec.tmpl b/gems/net_http_unix/net_http_unix.spec.tmpl index a8a7d90..18cacf4 100644 --- a/gems/net_http_unix/net_http_unix.spec.tmpl +++ b/gems/net_http_unix/net_http_unix.spec.tmpl @@ -20,8 +20,8 @@ BuildArch: noarch Wrapper around Net::HTTP with AF_UNIX support. %package puppet3 -Group: Development/Languages -Summary: Net_http_unix rubygem packaged for Puppet Enterprise 3.x agents +Group: Development/Languages +Summary: Net_http_unix rubygem packaged for Puppet Enterprise 3.x agents Requires: pe-ruby Requires: pe-rubygems Provides: pe-rubygem(%{gem_name}) = %{version} @@ -29,7 +29,7 @@ Provides: pe-rubygem-%{gem_name} = %{version} %description puppet3 %package puppet-aio -Group: Development/Languages +Group: Development/Languages Summary: Net_http_unix rubygem packaged for Puppet All-In-One (4.x) agents Requires: puppet >= 4.0.0 Provides: rubygem-%{gem_name} = %{version} From c5028bf46f38ecc163f01aac088f92d62802b418 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 7 Apr 2016 12:28:40 -0400 Subject: [PATCH 08/60] Limit rubocop version when running ruby 1.9 --- Gemfile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index db3a9d1..2cf0bc4 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,6 @@ gem 'net_http_unix' gem 'netaddr' group :development do - gem 'rubocop', '>=0.35.1' gem 'guard' gem 'guard-rspec' gem 'guard-rubocop' @@ -30,4 +29,15 @@ group :development, :test do gem 'simplecov-rcov', require: false end +# Rubocop > 0.37 requires a gem that only works with ruby 2.x +if RUBY_VERSION.to_f < 2.0 + group :development, :test do + gem 'rubocop', >=0.35.1', '< 0.38' + end +else + group :development, :test do + gem 'rubocop', >=0.35.1' + end +end + # vim:ft=ruby From e88df1b0ace88c545502bd85a4082e1a77af4cbd Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 7 Apr 2016 12:41:07 -0400 Subject: [PATCH 09/60] Fix missing quote --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 2cf0bc4..06c2edb 100644 --- a/Gemfile +++ b/Gemfile @@ -32,11 +32,11 @@ end # Rubocop > 0.37 requires a gem that only works with ruby 2.x if RUBY_VERSION.to_f < 2.0 group :development, :test do - gem 'rubocop', >=0.35.1', '< 0.38' + gem 'rubocop', '>=0.35.1', '< 0.38' end else group :development, :test do - gem 'rubocop', >=0.35.1' + gem 'rubocop', '>=0.35.1' end end From f172c3db889ca56d465af5d0f47254fd202c1326 Mon Sep 17 00:00:00 2001 From: Hunt Burdick Date: Fri, 22 Apr 2016 14:16:58 -0600 Subject: [PATCH 10/60] Validate array param options --- lib/rbeapi/api/dns.rb | 8 +++++-- lib/rbeapi/api/interfaces.rb | 2 ++ lib/rbeapi/api/ipinterfaces.rb | 4 ++++ lib/rbeapi/api/routemaps.rb | 21 +++++++++++++++++-- lib/rbeapi/api/switchports.rb | 2 +- lib/rbeapi/api/users.rb | 2 ++ lib/rbeapi/api/varp.rb | 4 ++++ lib/rbeapi/api/vrrp.rb | 9 ++++++++ spec/system/rbeapi/api/ipinterfaces_spec.rb | 5 +++++ .../rbeapi/api/interfaces/portchannel_spec.rb | 8 +++++++ .../unit/rbeapi/api/routemaps/default_spec.rb | 5 +++++ spec/unit/rbeapi/api/vrrp/default_spec.rb | 10 +++++++++ 12 files changed, 75 insertions(+), 5 deletions(-) diff --git a/lib/rbeapi/api/dns.rb b/lib/rbeapi/api/dns.rb index f2046d0..137faee 100644 --- a/lib/rbeapi/api/dns.rb +++ b/lib/rbeapi/api/dns.rb @@ -198,11 +198,11 @@ def remove_name_server(server) # no ip domain-list # default ip domain-list # - # @option value [Array] The set of domain names to configure on the + # @option opts value [Array] The set of domain names to configure on the # node. The list of domain names will be replace in the nodes running # configuration by the list provided in value. # - # @option default [Boolean] Configures the ip domain-list using the + # @option opts default [Boolean] Configures the ip domain-list using the # default keyword argument. # # @return [Boolean] Returns true if the commands completed successfully. @@ -211,6 +211,10 @@ def set_domain_list(opts = {}) enable = opts.fetch(:enable, true) default = opts[:default] || false + if value + fail ArgumentError, 'value must be an Array' unless value.is_a?(Array) + end + cmds = [] case default when true diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index 9efc667..fba5e72 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -843,6 +843,8 @@ def set_minimum_links(name, opts = {}) # # @return [Boolean] Returns true if the command completed successfully. def set_members(name, members, mode = nil) + fail ArgumentError, 'members must be an Array' unless members.is_a?(Array) + current_members = Set.new parse_members(name)[:members] members = Set.new members diff --git a/lib/rbeapi/api/ipinterfaces.rb b/lib/rbeapi/api/ipinterfaces.rb index c3a47e2..f8bc4ac 100644 --- a/lib/rbeapi/api/ipinterfaces.rb +++ b/lib/rbeapi/api/ipinterfaces.rb @@ -312,6 +312,10 @@ def set_helper_addresses(name, opts = {}) enable = opts.fetch(:enable, true) default = opts[:default] || false + if value + fail ArgumentError, 'value must be an Array' unless value.is_a?(Array) + end + case default when true cmds = 'default ip helper-address' diff --git a/lib/rbeapi/api/routemaps.rb b/lib/rbeapi/api/routemaps.rb index a05cfe4..8462f1d 100644 --- a/lib/rbeapi/api/routemaps.rb +++ b/lib/rbeapi/api/routemaps.rb @@ -220,10 +220,14 @@ def parse_rules(rules) mdata = /\s{3}(\w+)\s/.match(rule) case mdata.nil? ? nil : mdata[1] when 'match' - rule_hsh[:match] = [] unless rule_hsh.include?(:match) + unless rule_hsh.include?(:match) && rule_hsh[:match].is_a?(Array) + rule_hsh[:match] = [] + end rule_hsh[:match] << rule.sub('match', '').strip when 'set' - rule_hsh[:set] = [] unless rule_hsh.include?(:set) + unless rule_hsh.include?(:set) && rule_hsh[:set].is_a?(Array) + rule_hsh[:set] = [] + end rule_hsh[:set] << rule.sub('set', '').strip when 'continue' rule_hsh[:continue] = nil unless rule_hsh.include?(:continue) @@ -304,6 +308,11 @@ def create(name, action, seqno, opts = {}) if opts.empty? cmds = name_commands(name, action, seqno) else + if opts[:match] + unless opts[:match].is_a?(Array) + fail ArgumentError, 'opts match must be an Array' + end + end cmds = name_commands(name, action, seqno, opts) if opts[:description] cmds << 'no description' @@ -343,6 +352,8 @@ def create(name, action, seqno, opts = {}) # # @return [Boolean] Returns true if the command completed successfully. def remove_match_statements(name, action, seqno, cmds) + fail ArgumentError, 'cmds must be an Array' unless cmds.is_a?(Array) + entries = parse_entries(name) return nil unless entries entries.each do |entry| @@ -369,6 +380,8 @@ def remove_match_statements(name, action, seqno, cmds) # # @return [Boolean] Returns true if the command completed successfully. def remove_set_statements(name, action, seqno, cmds) + fail ArgumentError, 'cmds must be an Array' unless cmds.is_a?(Array) + entries = parse_entries(name) return nil unless entries entries.each do |entry| @@ -439,6 +452,8 @@ def default(name, action, seqno) # # @return [Boolean] Returns true if the command completed successfully. def set_match_statements(name, action, seqno, value) + fail ArgumentError, 'value must be an Array' unless value.is_a?(Array) + cmds = ["route-map #{name} #{action} #{seqno}"] remove_match_statements(name, action, seqno, cmds) Array(value).each do |options| @@ -464,6 +479,8 @@ def set_match_statements(name, action, seqno, value) # # @return [Boolean] Returns true if the command completed successfully. def set_set_statements(name, action, seqno, value) + fail ArgumentError, 'value must be an Array' unless value.is_a?(Array) + cmds = ["route-map #{name} #{action} #{seqno}"] remove_set_statements(name, action, seqno, cmds) Array(value).each do |options| diff --git a/lib/rbeapi/api/switchports.rb b/lib/rbeapi/api/switchports.rb index 16a3e62..5f8730b 100644 --- a/lib/rbeapi/api/switchports.rb +++ b/lib/rbeapi/api/switchports.rb @@ -264,7 +264,7 @@ def set_mode(name, opts = {}) # # @param opts [Hash] The configuration parameters for the interface. # - # @option ots value [Array] The list of vlan ids to configure on the + # @option opts value [Array] The list of vlan ids to configure on the # switchport to be allowed. This value must be an array of valid vlan # ids. # diff --git a/lib/rbeapi/api/users.rb b/lib/rbeapi/api/users.rb index 73c5ebd..f7ee470 100644 --- a/lib/rbeapi/api/users.rb +++ b/lib/rbeapi/api/users.rb @@ -149,6 +149,8 @@ def getall # # @return [Hash] Returns the resource hash attribute. def parse_user_entry(user) + fail ArgumentError, 'user must be an Array' unless user.is_a?(Array) + hsh = {} hsh[:name] = user[0] hsh[:privilege] = user[1].to_i diff --git a/lib/rbeapi/api/varp.rb b/lib/rbeapi/api/varp.rb index 69b6292..64fdc53 100644 --- a/lib/rbeapi/api/varp.rb +++ b/lib/rbeapi/api/varp.rb @@ -205,6 +205,10 @@ def set_addresses(name, opts = {}) default = opts[:default] || false cmds = ["interface #{name}"] + if value + fail ArgumentError, 'value must be an Array' unless value.is_a?(Array) + end + case default when true cmds << 'default ip virtual-router address' diff --git a/lib/rbeapi/api/vrrp.rb b/lib/rbeapi/api/vrrp.rb index 2a42ea7..677a4e2 100644 --- a/lib/rbeapi/api/vrrp.rb +++ b/lib/rbeapi/api/vrrp.rb @@ -512,6 +512,15 @@ def parse_delay_reload(config, vrid) # @return [Boolean] Returns true if the command completed successfully. def create(name, vrid, opts = {}) fail ArgumentError, 'create has no options set' if opts.empty? + + if opts[:secondary_ip] && !opts[:secondary_ip].is_a?(Array) + fail ArgumentError, 'opts secondary_ip must be an Array' + end + + if opts[:track] && !opts[:track].is_a?(Array) + fail ArgumentError, 'opts track must be an Array' + end + cmds = [] if opts.key?(:enable) if opts[:enable] diff --git a/spec/system/rbeapi/api/ipinterfaces_spec.rb b/spec/system/rbeapi/api/ipinterfaces_spec.rb index bd52f94..79ae48d 100644 --- a/spec/system/rbeapi/api/ipinterfaces_spec.rb +++ b/spec/system/rbeapi/api/ipinterfaces_spec.rb @@ -150,5 +150,10 @@ .to be_truthy expect(subject.get('Ethernet1')[:helper_addresses].sort).to be_empty end + + it 'raises an ArgumentError if opts value is not an array' do + expect { subject.set_helper_addresses('Ethernet1', value: '123') } + .to raise_error(ArgumentError) + end end end diff --git a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb index 2c04d88..0b098dd 100644 --- a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb @@ -141,4 +141,12 @@ def interfaces expect(subject.set_shutdown('Port-Channel1', opts)).to be_truthy end end + + describe '#set_members' do + it 'raises an ArgumentError if members is not an array' do + expect { subject.set_members('Port-Channel1', + 'Ethernet3') } + .to raise_error(ArgumentError) + end + end end diff --git a/spec/unit/rbeapi/api/routemaps/default_spec.rb b/spec/unit/rbeapi/api/routemaps/default_spec.rb index a80c886..19bbf30 100644 --- a/spec/unit/rbeapi/api/routemaps/default_spec.rb +++ b/spec/unit/rbeapi/api/routemaps/default_spec.rb @@ -244,6 +244,11 @@ def routemaps expect(subject.create('test', 'deny', 20, default: true)).to be_truthy end + + it 'raises an ArgumentError if opts match is not an array' do + expect { subject.create('test', 'permit', 10, match: '123') } + .to raise_error(ArgumentError) + end end describe '#delete' do diff --git a/spec/unit/rbeapi/api/vrrp/default_spec.rb b/spec/unit/rbeapi/api/vrrp/default_spec.rb index 60031ea..88698dc 100644 --- a/spec/unit/rbeapi/api/vrrp/default_spec.rb +++ b/spec/unit/rbeapi/api/vrrp/default_spec.rb @@ -169,6 +169,16 @@ def vrrp expect { subject.create('Vlan100', 9) }.to \ raise_error ArgumentError end + + it 'raises an ArgumentError if secondary_ip is not an array' do + expect { subject.create('Ethernet1', 9, secondary_ip: '123') } + .to raise_error(ArgumentError) + end + + it 'raises an ArgumentError if track is not an array' do + expect { subject.create('Ethernet1', 9, track: '123') } + .to raise_error(ArgumentError) + end end describe '#delete' do From fc54627d69e92bd7f0b15d8f60c643373d558637 Mon Sep 17 00:00:00 2001 From: Hunt Burdick Date: Mon, 25 Apr 2016 17:27:52 -0600 Subject: [PATCH 11/60] Adjustments to routemaps. --- lib/rbeapi/api/routemaps.rb | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/rbeapi/api/routemaps.rb b/lib/rbeapi/api/routemaps.rb index 8462f1d..e3591f7 100644 --- a/lib/rbeapi/api/routemaps.rb +++ b/lib/rbeapi/api/routemaps.rb @@ -220,14 +220,10 @@ def parse_rules(rules) mdata = /\s{3}(\w+)\s/.match(rule) case mdata.nil? ? nil : mdata[1] when 'match' - unless rule_hsh.include?(:match) && rule_hsh[:match].is_a?(Array) - rule_hsh[:match] = [] - end + rule_hsh[:match] = [] unless rule_hsh.include?(:match) rule_hsh[:match] << rule.sub('match', '').strip when 'set' - unless rule_hsh.include?(:set) && rule_hsh[:set].is_a?(Array) - rule_hsh[:set] = [] - end + rule_hsh[:set] = [] unless rule_hsh.include?(:set) rule_hsh[:set] << rule.sub('set', '').strip when 'continue' rule_hsh[:continue] = nil unless rule_hsh.include?(:continue) @@ -308,10 +304,8 @@ def create(name, action, seqno, opts = {}) if opts.empty? cmds = name_commands(name, action, seqno) else - if opts[:match] - unless opts[:match].is_a?(Array) - fail ArgumentError, 'opts match must be an Array' - end + if opts[:match] && !opts[:match].is_a?(Array) + fail ArgumentError, 'opts match must be an Array' end cmds = name_commands(name, action, seqno, opts) if opts[:description] From bccd26a445c6d846392743125efc8490eefa0ce4 Mon Sep 17 00:00:00 2001 From: Nick Wiecha Date: Thu, 24 Mar 2016 09:11:11 +0100 Subject: [PATCH 12/60] add load-interval function in BaseInterfaceClass --- lib/rbeapi/api/interfaces.rb | 45 +++++++++++++++++++ .../system/rbeapi/api/interfaces_base_spec.rb | 32 +++++++++++-- .../rbeapi/api/interfaces_ethernet_spec.rb | 28 +++++++++++- .../rbeapi/api/interfaces_portchannel_spec.rb | 28 +++++++++++- .../rbeapi/api/interfaces_vxlan_spec.rb | 28 +++++++++++- spec/unit/rbeapi/api/interfaces/base_spec.rb | 2 +- .../rbeapi/api/interfaces/ethernet_spec.rb | 2 +- .../rbeapi/api/interfaces/portchannel_spec.rb | 2 +- spec/unit/rbeapi/api/interfaces/vxlan_spec.rb | 2 +- 9 files changed, 159 insertions(+), 10 deletions(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index fba5e72..92dc12f 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -144,6 +144,7 @@ def respond_to?(method_name, name = nil) # that is common to all interfaces configured in EOS. class BaseInterface < Entity DEFAULT_INTF_DESCRIPTION = '' + DEFAULT_LOAD_INTERVAL = '' ## # get returns the specified interface resource hash that represents the @@ -157,6 +158,7 @@ class BaseInterface < Entity # type: 'generic' # description: # shutdown: [true, false] + # load_interval: # } # # @param name [String] The name of the interface to return from the @@ -172,6 +174,7 @@ def get(name) response = { name: name, type: 'generic' } response.merge!(parse_description(config)) response.merge!(parse_shutdown(config)) + response.merge!(parse_load_interval(config)) response end @@ -213,6 +216,24 @@ def parse_shutdown(config) end private :parse_shutdown + ## + # parse_load_interval scans the provided configuration block and + # parse the load-interval value. If the interface load-interval + # value is not configured, then this method will return the value of + # DEFAULT_LOAD_INTERVAL. The hash returned is intended to be merged into + # the interface resource hash. + # + # @api private + # + # @param config [String] The configuration block to parse. + # + # @return [Hash] Returns the resource hash attribute. + def parse_load_interval(config) + mdata = /load-interval (\w+)$/.match(config) + { load_interval: mdata.nil? ? DEFAULT_LOAD_INTERVAL : mdata[1] } + end + private :parse_load_interval + ## # create will create a new interface resource in the node's current # configuration with the specified interface name. If the create @@ -326,6 +347,27 @@ def set_shutdown(name, opts = {}) commands = command_builder('shutdown', opts) configure_interface(name, commands) end + + ## + # set_load_interval is a convenience function for configuring the + # value of interface load-interval + # + # @param name [String] The interface name to apply the configuration + # values to. The name must be the full interface identifier. + # + # @param opts [Hash] Optional keyword arguments. + # + # @option opts value [String] Specifies the value to configure the + # load-interval setting for. Valid values are between 5 and 600. + # + # @option opts default [Boolean] Configures the load-interval value on + # the interface using the default keyword. + # + # @return [Boolean] Returns true if the command completed successfully. + def set_load_interval(name, opts = {}) + commands = command_builder("load-interval", opts) + configure_interface(name, commands) + end end ## @@ -347,6 +389,7 @@ class EthernetInterface < BaseInterface # type: , # description: , # shutdown: , + # load_interval: # speed: , # forced: , # sflow: , @@ -654,6 +697,7 @@ class PortchannelInterface < BaseInterface # type: 'portchannel' # description: # shutdown: [true, false] + # load_interval: # members: array[] # lacp_mode: [active, passive, on] # minimum_links: @@ -1023,6 +1067,7 @@ class VxlanInterface < BaseInterface # type: , # description: , # shutdown: , + # load_interval: # source_interface: , # multicast_group: , # udp_port: , diff --git a/spec/system/rbeapi/api/interfaces_base_spec.rb b/spec/system/rbeapi/api/interfaces_base_spec.rb index ae27da1..2e40911 100644 --- a/spec/system/rbeapi/api/interfaces_base_spec.rb +++ b/spec/system/rbeapi/api/interfaces_base_spec.rb @@ -20,7 +20,7 @@ describe '#get' do context 'with interface Loopback' do let(:entity) do - { name: 'Loopback0', type: 'generic', description: '', shutdown: false } + { name: 'Loopback0', type: 'generic', description: '', shutdown: false, load_interval: '' } end before { node.config(['no interface Loopback0', 'interface Loopback0']) } @@ -33,7 +33,7 @@ context 'with interface Port-Channel' do let(:entity) do { name: 'Port-Channel1', type: 'portchannel', description: '', - shutdown: false, members: [], lacp_mode: 'on', minimum_links: '0', + shutdown: false, load_interval: '', members: [], lacp_mode: 'on', minimum_links: '0', lacp_fallback: 'disabled', lacp_timeout: '90' } end @@ -50,7 +50,7 @@ context 'with interface Vxlan' do let(:entity) do { name: 'Vxlan1', type: 'vxlan', description: '', - shutdown: false, source_interface: '', multicast_group: '', + shutdown: false, load_interval: '', source_interface: '', multicast_group: '', udp_port: 4789, flood_list: [], vlans: {} } end @@ -131,4 +131,30 @@ expect(subject.get('Loopback0')[:shutdown]).to be_falsy end end + + describe '#set_load_interval' do + before do + node.config(['interface Loopback0', 'default load-interval']) + end + + it 'sets the load-interval value on the interface' do + expect(subject.get('Loopback0')[:load_interval]).to eq('') + expect(subject.set_load_interval('Loopback0', value: '10')).to be_truthy + expect(subject.get('Loopback0')[:load_interval]).to eq('10') + end + + it 'negates the load-interval' do + expect(subject.set_load_interval('Loopback0', value: '20')).to be_truthy + expect(subject.get('Loopback0')[:load_interval]).to eq('20') + expect(subject.set_load_interval('Loopback0', enable: false)).to be_truthy + expect(subject.get('Loopback0')[:load_interval]).to eq('') + end + + it 'defaults the load-interval' do + expect(subject.set_load_interval('Loopback0', value: '10')).to be_truthy + expect(subject.get('Loopback0')[:load_interval]).to eq('10') + expect(subject.set_load_interval('Loopback0', default: true)).to be_truthy + expect(subject.get('Loopback0')[:load_interval]).to eq('') + end + end end diff --git a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb index 1940ef4..47ca1d0 100644 --- a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +++ b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb @@ -14,7 +14,7 @@ describe '#get' do let(:entity) do - { name: 'Ethernet1', type: 'ethernet', description: '', shutdown: false, + { name: 'Ethernet1', type: 'ethernet', description: '', shutdown: false, load_interval: '', speed: 'auto', forced: false, sflow: true, flowcontrol_send: 'off', flowcontrol_receive: 'off' } end @@ -150,4 +150,30 @@ expect(subject.get('Ethernet1')[:flowcontrol_receive]).to eq('off') end end + + describe '#set_load_interval' do + before do + node.config(['interface Ethernet1', 'default load-interval']) + end + + it 'sets the load-interval value on the interface' do + expect(subject.get('Ethernet1')[:load_interval]).to eq('') + expect(subject.set_load_interval('Ethernet1', value: '10')).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('10') + end + + it 'negates the load-interval' do + expect(subject.set_load_interval('Ethernet1', value: '20')).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('20') + expect(subject.set_load_interval('Ethernet1', enable: false)).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('') + end + + it 'defaults the load-interval' do + expect(subject.set_load_interval('Ethernet1', value: '10')).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('10') + expect(subject.set_load_interval('Ethernet1', default: true)).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('') + end + end end diff --git a/spec/system/rbeapi/api/interfaces_portchannel_spec.rb b/spec/system/rbeapi/api/interfaces_portchannel_spec.rb index 6814e98..9ac2a29 100644 --- a/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +++ b/spec/system/rbeapi/api/interfaces_portchannel_spec.rb @@ -14,7 +14,7 @@ describe '#get' do let(:entity) do { name: 'Port-Channel1', type: 'portchannel', description: '', - shutdown: false, members: [], lacp_mode: 'on', minimum_links: '0', + shutdown: false, load_interval: '', members: [], lacp_mode: 'on', minimum_links: '0', lacp_timeout: '90', lacp_fallback: 'disabled' } end @@ -270,4 +270,30 @@ expect(subject.get('Port-Channel1')[:lacp_timeout]).to eq('100') end end + + describe '#set_load_interval' do + before do + node.config(['interface Port-Channel1', 'default load-interval']) + end + + it 'sets the load-interval value on the interface' do + expect(subject.get('Port-Channel1')[:load_interval]).to eq('') + expect(subject.set_load_interval('Port-Channel1', value: '10')).to be_truthy + expect(subject.get('Port-Channel1')[:load_interval]).to eq('10') + end + + it 'negates the load-interval' do + expect(subject.set_load_interval('Port-Channel1', value: '20')).to be_truthy + expect(subject.get('Port-Channel1')[:load_interval]).to eq('20') + expect(subject.set_load_interval('Port-Channel1', enable: false)).to be_truthy + expect(subject.get('Port-Channel1')[:load_interval]).to eq('') + end + + it 'defaults the load-interval' do + expect(subject.set_load_interval('Port-Channel1', value: '10')).to be_truthy + expect(subject.get('Port-Channel1')[:load_interval]).to eq('10') + expect(subject.set_load_interval('Port-Channel1', default: true)).to be_truthy + expect(subject.get('Port-Channel1')[:load_interval]).to eq('') + end + end end diff --git a/spec/system/rbeapi/api/interfaces_vxlan_spec.rb b/spec/system/rbeapi/api/interfaces_vxlan_spec.rb index 89f91e0..cfb45e1 100644 --- a/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +++ b/spec/system/rbeapi/api/interfaces_vxlan_spec.rb @@ -13,7 +13,7 @@ describe '#get' do let(:entity) do - { name: 'Vxlan1', type: 'vxlan', description: '', shutdown: false, + { name: 'Vxlan1', type: 'vxlan', description: '', shutdown: false, load_interval: '', source_interface: '', multicast_group: '', udp_port: 4789, flood_list: [], vlans: {} } end @@ -91,6 +91,32 @@ end end + describe '#set_load_interval' do + before do + node.config(['interface Vxlan1', 'default load-interval']) + end + + it 'sets the load-interval value on the interface' do + expect(subject.get('Vxlan1')[:load_interval]).to eq('') + expect(subject.set_load_interval('Vxlan1', value: '10')).to be_truthy + expect(subject.get('Vxlan1')[:load_interval]).to eq('10') + end + + it 'negates the load-interval' do + expect(subject.set_load_interval('Vxlan1', value: '20')).to be_truthy + expect(subject.get('Vxlan1')[:load_interval]).to eq('20') + expect(subject.set_load_interval('Vxlan1', enable: false)).to be_truthy + expect(subject.get('Vxlan1')[:load_interval]).to eq('') + end + + it 'defaults the load-interval' do + expect(subject.set_load_interval('Vxlan1', value: '10')).to be_truthy + expect(subject.get('Vxlan1')[:load_interval]).to eq('10') + expect(subject.set_load_interval('Vxlan1', default: true)).to be_truthy + expect(subject.get('Vxlan1')[:load_interval]).to eq('') + end + end + describe '#set_source_interface' do before { node.config(['no interface Vxlan1', 'interface Vxlan1']) } diff --git a/spec/unit/rbeapi/api/interfaces/base_spec.rb b/spec/unit/rbeapi/api/interfaces/base_spec.rb index bc20b94..476a89d 100644 --- a/spec/unit/rbeapi/api/interfaces/base_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/base_spec.rb @@ -23,7 +23,7 @@ def interfaces let(:resource) { subject.get('Loopback0') } let(:keys) do - [:type, :shutdown, :description, :name] + [:type, :shutdown, :load_interval, :description, :name] end it 'returns an ethernet resource as a hash' do diff --git a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb index 1fae3bb..237d3ab 100644 --- a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb @@ -24,7 +24,7 @@ def interfaces let(:keys) do [:type, :speed, :sflow, :flowcontrol_send, :flowcontrol_receive, - :forced, :shutdown, :description, :name] + :forced, :shutdown, :description, :name, :load_interval] end it 'returns an ethernet resource as a hash' do diff --git a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb index 0b098dd..4a44988 100644 --- a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb @@ -31,7 +31,7 @@ def interfaces let(:resource) { subject.get('Port-Channel1') } let(:keys) do - [:type, :shutdown, :description, :name, :members, :lacp_mode, + [:type, :shutdown, :load_interval, :description, :name, :members, :lacp_mode, :minimum_links, :lacp_timeout, :lacp_fallback] end diff --git a/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb b/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb index eada50b..4c6b0fb 100644 --- a/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb @@ -23,7 +23,7 @@ def interfaces let(:resource) { subject.get('Vxlan1') } let(:keys) do - [:type, :shutdown, :description, :name, :source_interface, + [:type, :shutdown, :load_interval, :description, :name, :source_interface, :multicast_group, :udp_port, :flood_list, :vlans] end From ea283f3ac9743ebb978495c7e38486b09b23a859 Mon Sep 17 00:00:00 2001 From: Nick Wiecha Date: Mon, 4 Apr 2016 11:18:38 +0200 Subject: [PATCH 13/60] add load-interval function for ipinterfaces --- lib/rbeapi/api/ipinterfaces.rb | 44 +++++++++++++++++++++ spec/system/rbeapi/api/ipinterfaces_spec.rb | 28 ++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/api/ipinterfaces.rb b/lib/rbeapi/api/ipinterfaces.rb index f8bc4ac..8451778 100644 --- a/lib/rbeapi/api/ipinterfaces.rb +++ b/lib/rbeapi/api/ipinterfaces.rb @@ -42,6 +42,7 @@ module Api # IP interfaces configured using eAPI. class Ipinterfaces < Entity DEFAULT_ADDRESS = '' + DEFAULT_LOAD_INTERVAL = '' ## # get returns a resource hash that represents the configuration of the IP @@ -52,6 +53,7 @@ class Ipinterfaces < Entity # address: , # mtu: , # helper_addresses: array + # load_interval: # } # # @param name [String] The full interface identifier of the interface to @@ -70,6 +72,7 @@ def get(name) response.merge!(parse_address(config)) response.merge!(parse_mtu(config)) response.merge!(parse_helper_addresses(config)) + response.merge!(parse_load_interval(config)) response end @@ -83,11 +86,13 @@ def get(name) # address: , # mtu: , # helper_addresses: array + # load_interval: # }, # : { # address: , # mtu: , # helper_addresses: array + # load_interval: # }, # ... # } @@ -162,6 +167,24 @@ def parse_helper_addresses(config) end private :parse_helper_addresses + ## + # parse_load_interval scans the provided configuration block and + # parse the load-interval value. If the interface load-interval + # value is not configured, then this method will return the value of + # DEFAULT_LOAD_INTERVAL. The hash returned is intended to be merged into + # the interface resource hash. + # + # @api private + # + # @param config [String] The configuration block to parse. + # + # @return [Hash] Returns the resource hash attribute. + def parse_load_interval(config) + mdata = /load-interval (\w+)$/.match(config) + { load_interval: mdata.nil? ? DEFAULT_LOAD_INTERVAL : mdata[1] } + end + private :parse_load_interval + ## # create will create a new IP interface on the node. If the ip interface # already exists in the configuration, this method will still return @@ -325,6 +348,27 @@ def set_helper_addresses(name, opts = {}) end configure_interface(name, cmds) end + + ## + # set_load_interval is a convenience function for configuring the + # value of interface load-interval + # + # @param name [String] The interface name to apply the configuration + # values to. The name must be the full interface identifier. + # + # @param opts [Hash] Optional keyword arguments. + # + # @option opts value [String] Specifies the value to configure the + # load-interval setting for. Valid values are between 5 and 600. + # + # @option opts default [Boolean] Configures the load-interval value on + # the interface using the default keyword. + # + # @return [Boolean] Returns true if the command completed successfully. + def set_load_interval(name, opts = {}) + cmds = command_builder("load-interval", opts) + configure_interface(name, cmds) + end end end end diff --git a/spec/system/rbeapi/api/ipinterfaces_spec.rb b/spec/system/rbeapi/api/ipinterfaces_spec.rb index 79ae48d..dee6a68 100644 --- a/spec/system/rbeapi/api/ipinterfaces_spec.rb +++ b/spec/system/rbeapi/api/ipinterfaces_spec.rb @@ -13,7 +13,7 @@ describe '#get' do let(:entity) do - { address: '77.99.99.99/24', mtu: '1500', helper_addresses: [] } + { address: '77.99.99.99/24', mtu: '1500', helper_addresses: [], load_interval: '' } end before do @@ -156,4 +156,30 @@ .to raise_error(ArgumentError) end end + + describe '#set_load_interval' do + before do + node.config(['default interface Ethernet1', 'interface Ethernet1', 'no switchport']) + end + + it 'sets the load-interval value on the interface' do + expect(subject.get('Ethernet1')[:load_interval]).to eq('') + expect(subject.set_load_interval('Ethernet1', value: '10')).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('10') + end + + it 'negates the load-interval' do + expect(subject.set_load_interval('Ethernet1', value: '20')).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('20') + expect(subject.set_load_interval('Ethernet1', enable: false)).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('') + end + + it 'defaults the load-interval' do + expect(subject.set_load_interval('Ethernet1', value: '10')).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('10') + expect(subject.set_load_interval('Ethernet1', default: true)).to be_truthy + expect(subject.get('Ethernet1')[:load_interval]).to eq('') + end + end end From 4964362e4142b1e77119d332c835e672a46a576a Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Thu, 1 Sep 2016 15:03:43 +0200 Subject: [PATCH 14/60] fix interface speed functions --- lib/rbeapi/api/interfaces.rb | 25 +++++-------------- .../rbeapi/api/interfaces_ethernet_spec.rb | 13 +++------- .../rbeapi/api/interfaces/ethernet_spec.rb | 2 +- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index 92dc12f..a4639f5 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -376,8 +376,7 @@ def set_load_interval(name, opts = {}) class EthernetInterface < BaseInterface DEFAULT_ETH_FLOWC_TX = 'off' DEFAULT_ETH_FLOWC_RX = 'off' - DEFAULT_SPEED = 'auto' - DEFAULT_FORCED = false + DEFAULT_SPEED = 'default' ## # get returns the specified Ethernet interface resource hash that @@ -391,7 +390,6 @@ class EthernetInterface < BaseInterface # shutdown: , # load_interval: # speed: , - # forced: , # sflow: , # flowcontrol_send: , # flowcontrol_receive: @@ -429,10 +427,8 @@ def get(name) # # @return [Hash] Returns the resource hash attribute. def parse_speed(config) - value = config.scan(/speed (forced)?[ ]?(\w+)/).first - return { speed: DEFAULT_SPEED, forced: DEFAULT_FORCED } unless value - (forced, value) = value.first - { speed: value, forced: !forced.nil? } + value = config.scan(/speed (.*)/).first + { speed: value.nil? ? DEFAULT_SPEED : value } end private :parse_speed @@ -537,28 +533,19 @@ def delete(_name) # @option opts enable [Boolean] If false then the command is # negated. Default is true. # - # @option opts forced [Boolean] Specifies if auto negotiation should be - # enabled (true) or disabled (false). - # - # @option opts default [Boolean] Configures the sflow value on the - # interface using the default keyword. - # # @return [Boolean] Returns true if the command completed successfully. def set_speed(name, opts = {}) value = opts[:value] - forced = opts.fetch(:forced, false) enable = opts.fetch(:enable, true) - default = opts.fetch(:default, false) - - forced = 'forced' if forced - forced = '' if value == 'auto' + default = (value == "default") cmds = ["interface #{name}"] case default when true cmds << 'default speed' when false - cmds << enable ? "speed #{forced} #{value}" : 'no speed' + cmd = enable ? "speed #{value}" : 'no speed' + cmds << cmd end configure cmds end diff --git a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb index 47ca1d0..4d9e9aa 100644 --- a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +++ b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb @@ -14,9 +14,9 @@ describe '#get' do let(:entity) do - { name: 'Ethernet1', type: 'ethernet', description: '', shutdown: false, load_interval: '', - speed: 'auto', forced: false, sflow: true, flowcontrol_send: 'off', - flowcontrol_receive: 'off' } + { name: 'Ethernet1', type: 'ethernet', description: '', shutdown: false, + load_interval: '', speed: 'default', sflow: true, + flowcontrol_send: 'off', flowcontrol_receive: 'off' } end before { node.config(['default interface Ethernet1']) } @@ -89,13 +89,8 @@ describe '#set_speed' do before { node.config(['default interface Ethernet1']) } - it 'sets default true' do - expect(subject.set_speed('Ethernet1', default: true)).to be_truthy - end - it 'sets enable true' do - expect(subject.set_speed('Ethernet1', default: false, - enable: true)).to be_falsy + expect(subject.set_speed('Ethernet1', enable: true)).to be_falsy end end diff --git a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb index 237d3ab..bd9b805 100644 --- a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb @@ -24,7 +24,7 @@ def interfaces let(:keys) do [:type, :speed, :sflow, :flowcontrol_send, :flowcontrol_receive, - :forced, :shutdown, :description, :name, :load_interval] + :shutdown, :description, :name, :load_interval] end it 'returns an ethernet resource as a hash' do From 3305a3ff496b0bd67a292d1d45ea42581f555fd7 Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Thu, 1 Sep 2016 15:32:34 +0200 Subject: [PATCH 15/60] fix interface parser to return a value instead an array --- lib/rbeapi/api/interfaces.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index a4639f5..6549bdb 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -428,7 +428,7 @@ def get(name) # @return [Hash] Returns the resource hash attribute. def parse_speed(config) value = config.scan(/speed (.*)/).first - { speed: value.nil? ? DEFAULT_SPEED : value } + { speed: value.nil? ? DEFAULT_SPEED : value.first } end private :parse_speed From e3affaeea9668286ef9e18d15a5f670c12f23919 Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Thu, 1 Sep 2016 16:05:46 +0200 Subject: [PATCH 16/60] fix default speed value --- lib/rbeapi/api/interfaces.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index 6549bdb..812ef05 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -537,7 +537,7 @@ def delete(_name) def set_speed(name, opts = {}) value = opts[:value] enable = opts.fetch(:enable, true) - default = (value == "default") + default = (value == :default) cmds = ["interface #{name}"] case default @@ -547,6 +547,7 @@ def set_speed(name, opts = {}) cmd = enable ? "speed #{value}" : 'no speed' cmds << cmd end + configure cmds end From 05cd8b2c2b2b34f21d0fb0cd93f53af195c7f558 Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Fri, 2 Sep 2016 08:56:47 +0200 Subject: [PATCH 17/60] add lacp piority support for ethernet interface --- lib/rbeapi/api/interfaces.rb | 50 +++++++++++++++++++ .../rbeapi/api/interfaces_ethernet_spec.rb | 34 ++++++++++++- .../rbeapi/api/interfaces/ethernet_spec.rb | 2 +- 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index 812ef05..b314a16 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -377,6 +377,7 @@ class EthernetInterface < BaseInterface DEFAULT_ETH_FLOWC_TX = 'off' DEFAULT_ETH_FLOWC_RX = 'off' DEFAULT_SPEED = 'default' + DEFAULT_LACP_PORT_PRIO = 32768 ## # get returns the specified Ethernet interface resource hash that @@ -393,6 +394,7 @@ class EthernetInterface < BaseInterface # sflow: , # flowcontrol_send: , # flowcontrol_receive: + # lacp_port_priority: # } # # @param name [String] The interface name to return a resource hash @@ -412,6 +414,7 @@ def get(name) response.merge!(parse_sflow(config)) response.merge!(parse_flowcontrol_send(config)) response.merge!(parse_flowcontrol_receive(config)) + response.merge!(parse_lacp_port_priority(config)) response end @@ -485,6 +488,24 @@ def parse_flowcontrol_receive(config) end private :parse_flowcontrol_receive + ## + # parse_lacp_port_priority scans the provided configuration block and + # parse the lacp port-priority value. If the interface lacp port-priority + # value is not configured, then this method will return the value of + # DEFAULT_LACP_PORT_PRIO. The hash returned is intended to be merged into + # the interface resource hash. + # + # @api private + # + # @param config [String] The configuration block to parse. + # + # @return [Hash] Returns the resource hash attribute. + def parse_lacp_port_priority(config) + mdata = /lacp port-priority (\d+)$/.match(config) + { lacp_port_priority: mdata.nil? ? DEFAULT_LACP_PORT_PRIO : mdata[1] } + end + private :parse_lacp_port_priority + ## # create overrides the create method from the BaseInterface and raises # an exception because Ethernet interface creation is not supported. @@ -664,6 +685,35 @@ def set_flowcontrol_send(name, opts = {}) def set_flowcontrol_receive(name, opts = {}) set_flowcontrol(name, 'receive', opts) end + + ## + # set_lacp_port_priority configures the lacp port-priority on the + # interface. Setting the enable keyword to true enables the lacp + # port-priority on the interface and setting enable to false disables + # the lacp port-priority on the interface. + # If the default keyword is set to true, then the lacp port-priority + # value is defaulted using the default keyword. The default keyword takes + # precedence over the enable keyword + # + # @since eos_version 4.13.7M + # + # @param name [String] The interface name to apply the configuration + # values to. The name must be the full interface identifier. + # + # @param opts [Hash] Optional keyword arguments. + # + # @option opts enable [Boolean] Enables sflow if the value is true or + # disables the lacp port-priority on the interface if false. Default is + # true. + # + # @option opts default [Boolean] Configures the lacp port-priority value + # on the interface using the default keyword. + # + # @return [Boolean] Returns true if the command completed successfully. + def set_lacp_port_priority(name, opts = {}) + commands = command_builder('lacp port-priority', opts) + configure_interface(name, commands) + end end ## diff --git a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb index 4d9e9aa..dda2fa9 100644 --- a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +++ b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb @@ -16,7 +16,8 @@ let(:entity) do { name: 'Ethernet1', type: 'ethernet', description: '', shutdown: false, load_interval: '', speed: 'default', sflow: true, - flowcontrol_send: 'off', flowcontrol_receive: 'off' } + flowcontrol_send: 'off', flowcontrol_receive: 'off', + lacp_port_priority: '32768' } end before { node.config(['default interface Ethernet1']) } @@ -171,4 +172,35 @@ expect(subject.get('Ethernet1')[:load_interval]).to eq('') end end + + describe '#set_lacp_port_priority' do + before do + node.config(['interface Ethernet1', 'default lacp port-priority']) + end + + it 'sets the lacp port-priority value on the interface' do + expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('32768') + expect(subject.set_lacp_port_priority('Ethernet1', value: '0')) + .to be_truthy + expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('0') + end + + it 'negates the lacp port-priority' do + expect(subject.set_lacp_port_priority('Ethernet1', value: '1')) + .to be_truthy + expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('1') + expect(subject.set_lacp_port_priority('Ethernet1', enable: false)) + .to be_truthy + expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('32768') + end + + it 'defaults the lacp port-priority' do + expect(subject.set_lacp_port_priority('Ethernet1', value: '2')) + .to be_truthy + expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('2') + expect(subject.set_lacp_port_priority('Ethernet1', default: true)) + .to be_truthy + expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('32768') + end + end end diff --git a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb index bd9b805..4837c12 100644 --- a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb @@ -24,7 +24,7 @@ def interfaces let(:keys) do [:type, :speed, :sflow, :flowcontrol_send, :flowcontrol_receive, - :shutdown, :description, :name, :load_interval] + :shutdown, :description, :name, :load_interval, :lacp_port_priority] end it 'returns an ethernet resource as a hash' do From f2335ca0f90793eb06e3c114d64331dfd4680542 Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Fri, 2 Sep 2016 10:09:13 +0200 Subject: [PATCH 18/60] rename lacp_port_priority to lacp_priority --- lib/rbeapi/api/interfaces.rb | 30 +++++++++--------- .../rbeapi/api/interfaces_ethernet_spec.rb | 31 ++++++++----------- .../rbeapi/api/interfaces/ethernet_spec.rb | 2 +- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index b314a16..b004d98 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -377,7 +377,7 @@ class EthernetInterface < BaseInterface DEFAULT_ETH_FLOWC_TX = 'off' DEFAULT_ETH_FLOWC_RX = 'off' DEFAULT_SPEED = 'default' - DEFAULT_LACP_PORT_PRIO = 32768 + DEFAULT_LACP_PRIORITY = 32768 ## # get returns the specified Ethernet interface resource hash that @@ -394,7 +394,7 @@ class EthernetInterface < BaseInterface # sflow: , # flowcontrol_send: , # flowcontrol_receive: - # lacp_port_priority: + # lacp_priority: # } # # @param name [String] The interface name to return a resource hash @@ -414,7 +414,7 @@ def get(name) response.merge!(parse_sflow(config)) response.merge!(parse_flowcontrol_send(config)) response.merge!(parse_flowcontrol_receive(config)) - response.merge!(parse_lacp_port_priority(config)) + response.merge!(parse_lacp_priority(config)) response end @@ -489,10 +489,10 @@ def parse_flowcontrol_receive(config) private :parse_flowcontrol_receive ## - # parse_lacp_port_priority scans the provided configuration block and - # parse the lacp port-priority value. If the interface lacp port-priority - # value is not configured, then this method will return the value of - # DEFAULT_LACP_PORT_PRIO. The hash returned is intended to be merged into + # parse_lacp_priority scans the provided configuration block and parse + # the lacp port-priority value. If the interface lacp port-priority value + # is not configured, then this method will return the value of + # DEFAULT_LACP_PRIORITY. The hash returned is intended to be merged into # the interface resource hash. # # @api private @@ -500,11 +500,11 @@ def parse_flowcontrol_receive(config) # @param config [String] The configuration block to parse. # # @return [Hash] Returns the resource hash attribute. - def parse_lacp_port_priority(config) + def parse_lacp_priority(config) mdata = /lacp port-priority (\d+)$/.match(config) - { lacp_port_priority: mdata.nil? ? DEFAULT_LACP_PORT_PRIO : mdata[1] } + { lacp_priority: mdata.nil? ? DEFAULT_LACP_PRIORITY : mdata[1] } end - private :parse_lacp_port_priority + private :parse_lacp_priority ## # create overrides the create method from the BaseInterface and raises @@ -687,10 +687,10 @@ def set_flowcontrol_receive(name, opts = {}) end ## - # set_lacp_port_priority configures the lacp port-priority on the - # interface. Setting the enable keyword to true enables the lacp - # port-priority on the interface and setting enable to false disables - # the lacp port-priority on the interface. + # set_lacp_priority configures the lacp port-priority on the interface. + # Setting the enable keyword to true enables the lacp port-priority on + # the interface and setting enable to false disables the lacp + # port-priority on the interface. # If the default keyword is set to true, then the lacp port-priority # value is defaulted using the default keyword. The default keyword takes # precedence over the enable keyword @@ -710,7 +710,7 @@ def set_flowcontrol_receive(name, opts = {}) # on the interface using the default keyword. # # @return [Boolean] Returns true if the command completed successfully. - def set_lacp_port_priority(name, opts = {}) + def set_lacp_priority(name, opts = {}) commands = command_builder('lacp port-priority', opts) configure_interface(name, commands) end diff --git a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb index dda2fa9..4b30aa2 100644 --- a/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +++ b/spec/system/rbeapi/api/interfaces_ethernet_spec.rb @@ -17,7 +17,7 @@ { name: 'Ethernet1', type: 'ethernet', description: '', shutdown: false, load_interval: '', speed: 'default', sflow: true, flowcontrol_send: 'off', flowcontrol_receive: 'off', - lacp_port_priority: '32768' } + lacp_priority: '32768' } end before { node.config(['default interface Ethernet1']) } @@ -173,34 +173,29 @@ end end - describe '#set_lacp_port_priority' do + describe '#set_lacp_priority' do before do node.config(['interface Ethernet1', 'default lacp port-priority']) end it 'sets the lacp port-priority value on the interface' do - expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('32768') - expect(subject.set_lacp_port_priority('Ethernet1', value: '0')) - .to be_truthy - expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('0') + expect(subject.get('Ethernet1')[:lacp_priority]).to eq('32768') + expect(subject.set_lacp_priority('Ethernet1', value: '0')).to be_truthy + expect(subject.get('Ethernet1')[:lacp_priority]).to eq('0') end it 'negates the lacp port-priority' do - expect(subject.set_lacp_port_priority('Ethernet1', value: '1')) - .to be_truthy - expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('1') - expect(subject.set_lacp_port_priority('Ethernet1', enable: false)) - .to be_truthy - expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('32768') + expect(subject.set_lacp_priority('Ethernet1', value: '1')).to be_truthy + expect(subject.get('Ethernet1')[:lacp_priority]).to eq('1') + expect(subject.set_lacp_priority('Ethernet1', enable: false)).to be_truthy + expect(subject.get('Ethernet1')[:lacp_priority]).to eq('32768') end it 'defaults the lacp port-priority' do - expect(subject.set_lacp_port_priority('Ethernet1', value: '2')) - .to be_truthy - expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('2') - expect(subject.set_lacp_port_priority('Ethernet1', default: true)) - .to be_truthy - expect(subject.get('Ethernet1')[:lacp_port_priority]).to eq('32768') + expect(subject.set_lacp_priority('Ethernet1', value: '2')).to be_truthy + expect(subject.get('Ethernet1')[:lacp_priority]).to eq('2') + expect(subject.set_lacp_priority('Ethernet1', default: true)).to be_truthy + expect(subject.get('Ethernet1')[:lacp_priority]).to eq('32768') end end end diff --git a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb index 4837c12..527b0f8 100644 --- a/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb @@ -24,7 +24,7 @@ def interfaces let(:keys) do [:type, :speed, :sflow, :flowcontrol_send, :flowcontrol_receive, - :shutdown, :description, :name, :load_interval, :lacp_port_priority] + :shutdown, :description, :name, :load_interval, :lacp_priority] end it 'returns an ethernet resource as a hash' do From 8115acebf297c300c803e919dce8ede11a60601f Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Mon, 5 Sep 2016 07:23:15 +0200 Subject: [PATCH 19/60] add switchport allowed vlan range capability, change allowed vlan from int to string --- lib/rbeapi/api/switchports.rb | 14 ++++--------- spec/system/rbeapi/api/switchports_spec.rb | 20 ++++++++++--------- .../rbeapi/api/switchports/default_spec.rb | 7 +++---- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/lib/rbeapi/api/switchports.rb b/lib/rbeapi/api/switchports.rb index 5f8730b..1f42006 100644 --- a/lib/rbeapi/api/switchports.rb +++ b/lib/rbeapi/api/switchports.rb @@ -136,12 +136,7 @@ def parse_trunk_allowed_vlans(config) return { trunk_allowed_vlans: [] } unless mdata[1] != 'none' vlans = mdata[1].split(',') values = vlans.each_with_object([]) do |vlan, arry| - if /-/ !~ vlan - arry << vlan.to_i - else - range_start, range_end = vlan.split('-') - arry.push(*Array(range_start.to_i..range_end.to_i)) - end + arry << vlan.to_s end { trunk_allowed_vlans: values } end @@ -266,7 +261,7 @@ def set_mode(name, opts = {}) # # @option opts value [Array] The list of vlan ids to configure on the # switchport to be allowed. This value must be an array of valid vlan - # ids. + # ids or vlan ranges. # # @option opts enable [Boolean] If false then the command is # negated. Default is true. @@ -283,7 +278,7 @@ def set_trunk_allowed_vlans(name, opts = {}) if value fail ArgumentError, 'value must be an Array' unless value.is_a?(Array) - value = value.map(&:inspect).join(',') + value = value.map(&:inspect).join(',').tr('"', '') end case default @@ -293,8 +288,7 @@ def set_trunk_allowed_vlans(name, opts = {}) if !enable cmds = 'no switchport trunk allowed vlan' else - cmds = ['switchport trunk allowed vlan none', - "switchport trunk allowed vlan #{value}"] + cmds = ["switchport trunk allowed vlan #{value}"] end end configure_interface(name, cmds) diff --git a/spec/system/rbeapi/api/switchports_spec.rb b/spec/system/rbeapi/api/switchports_spec.rb index 65740d0..b540ec6 100644 --- a/spec/system/rbeapi/api/switchports_spec.rb +++ b/spec/system/rbeapi/api/switchports_spec.rb @@ -191,34 +191,36 @@ .to raise_error(ArgumentError) end - it 'sets vlan 8 and 9 to the trunk allowed vlans' do + it 'sets vlan 8-10 and 100 to the trunk allowed vlans' do node.config(['interface Ethernet1', 'switchport trunk allowed vlan none']) expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: [8, 9])) + expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', '100'])) .to be_truthy - expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq([8, 9]) + expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['8-10', '100']) end it 'negate switchport trunk allowed vlan' do node.config(['interface Ethernet1', 'switchport trunk allowed vlan none']) expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: [8, 9])) + expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', '100'])) .to be_truthy - expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq([8, 9]) + expect(subject.get('Ethernet1')[:trunk_allowed_vlans]) + .to eq(['8-10', '100']) expect(subject.set_trunk_allowed_vlans('Ethernet1', enable: false)) .to be_truthy - expect(subject.get('Ethernet1')[:trunk_allowed_vlans].length).to eq(4094) + expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['1-4094']) end it 'default switchport trunk allowed vlan' do node.config(['interface Ethernet1', 'switchport trunk allowed vlan none']) expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: [8, 9])) + expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', '100'])) .to be_truthy - expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq([8, 9]) + expect(subject.get('Ethernet1')[:trunk_allowed_vlans]) + .to eq(['8-10', '100']) expect(subject.set_trunk_allowed_vlans('Ethernet1', default: true)) .to be_truthy - expect(subject.get('Ethernet1')[:trunk_allowed_vlans].length).to eq(4094) + expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['1-4094']) end end diff --git a/spec/unit/rbeapi/api/switchports/default_spec.rb b/spec/unit/rbeapi/api/switchports/default_spec.rb index 6217276..5efded3 100644 --- a/spec/unit/rbeapi/api/switchports/default_spec.rb +++ b/spec/unit/rbeapi/api/switchports/default_spec.rb @@ -195,11 +195,10 @@ def switchports .to raise_error(ArgumentError) end - it 'sets vlan 8 and 9 to the trunk allowed vlans' do + it 'sets vlan 8-10 and 100 to the trunk allowed vlans' do expect(node).to receive(:config) - .with(['interface Ethernet1', 'switchport trunk allowed vlan none', - 'switchport trunk allowed vlan 8,9']) - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: [8, 9])) + .with(['interface Ethernet1', 'switchport trunk allowed vlan 8-10,100']) + expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10','100'])) .to be_truthy end From 1a28ccc69d2fa4999e24147063c9ba484feee854 Mon Sep 17 00:00:00 2001 From: Florin Vinti Date: Wed, 7 Sep 2016 14:01:20 +0200 Subject: [PATCH 20/60] fix issue #142 - multicast group parsing when not configured --- lib/rbeapi/api/interfaces.rb | 6 ++++-- spec/system/rbeapi/api/interfaces_base_spec.rb | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index 92dc12f..75bf43b 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -1122,11 +1122,13 @@ def parse_source_interface(config) # @api private # # @param config [String] The interface configuration block to extract - # the vxlan multicast-group value from. + # the vxlan multicast-group value from. Note the configuration line + # 'vxlan multicast-group decap' is excluded so the multicast group + # value is correctly assigned '' when not defined. # # @return [Hash] def parse_multicast_group(config) - mdata = /multicast-group ([^\s]+)$/.match(config) + mdata = /multicast-group (?!decap)([^\s]+)$/.match(config) { multicast_group: mdata ? mdata[1] : DEFAULT_MCAST_GRP } end private :parse_multicast_group diff --git a/spec/system/rbeapi/api/interfaces_base_spec.rb b/spec/system/rbeapi/api/interfaces_base_spec.rb index 2e40911..6ea705a 100644 --- a/spec/system/rbeapi/api/interfaces_base_spec.rb +++ b/spec/system/rbeapi/api/interfaces_base_spec.rb @@ -61,6 +61,20 @@ it 'returns the interface resource' do expect(subject.get('Vxlan1')).to eq(entity) end + + let(:entity) do + { name: 'Vxlan1', type: 'vxlan', description: '', + shutdown: false, load_interval: '', source_interface: '', multicast_group: '224.0.2.0', + udp_port: 4789, flood_list: [], vlans: {} } + end + + before do + node.config(['no interface Vxlan1', 'interface Vxlan1', 'vxlan multicast-group 224.0.2.0']) + end + + it 'returns the interface resource with multicast group set' do + expect(subject.get('Vxlan1')).to eq(entity) + end end end From 462231d5893f61168ebc9f3be0fddb9044eab047 Mon Sep 17 00:00:00 2001 From: Florin Vinti Date: Wed, 7 Sep 2016 16:02:57 +0200 Subject: [PATCH 21/60] more robust regex for multicast group parsing --- lib/rbeapi/api/interfaces.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index 75bf43b..28a9f3b 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -1122,13 +1122,11 @@ def parse_source_interface(config) # @api private # # @param config [String] The interface configuration block to extract - # the vxlan multicast-group value from. Note the configuration line - # 'vxlan multicast-group decap' is excluded so the multicast group - # value is correctly assigned '' when not defined. + # the vxlan multicast-group value from. # # @return [Hash] def parse_multicast_group(config) - mdata = /multicast-group (?!decap)([^\s]+)$/.match(config) + mdata = /^\s*vxlan multicast-group ([^\s]+)$/.match(config) { multicast_group: mdata ? mdata[1] : DEFAULT_MCAST_GRP } end private :parse_multicast_group From 2f424d713a5009525f1a6dbba98f73b219029129 Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Wed, 7 Sep 2016 17:06:05 +0200 Subject: [PATCH 22/60] fix parse_instances to return the default instances and add tests --- lib/rbeapi/api/stp.rb | 9 ++-- spec/system/rbeapi/api/stp_instances_spec.rb | 53 ++++++++++++++++++-- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/lib/rbeapi/api/stp.rb b/lib/rbeapi/api/stp.rb index 34bfef3..d0cde00 100644 --- a/lib/rbeapi/api/stp.rb +++ b/lib/rbeapi/api/stp.rb @@ -196,15 +196,18 @@ def getall ## # parse_instances will scan the nodes current configuration and extract - # the list of configured mst instances. If no instances are configured - # then this method will return an empty array. + # the list of configured mst instances. Instances 0 and 1 are defined by + # default in the switch config and are always returned, even if not + # visible in the 'spanning-tree mst configuration' config section. # # @api private # # @return [Array] Returns an Array of configured stp instances. def parse_instances config = get_block('spanning-tree mst configuration') - config.scan(/(?<=^\s{3}instance\s)\d+/) + response = config.scan(/(?<=^\s{3}instance\s)\d+/) + response.push("0", "1").uniq! + response end private :parse_instances diff --git a/spec/system/rbeapi/api/stp_instances_spec.rb b/spec/system/rbeapi/api/stp_instances_spec.rb index 3170751..60cc943 100644 --- a/spec/system/rbeapi/api/stp_instances_spec.rb +++ b/spec/system/rbeapi/api/stp_instances_spec.rb @@ -15,14 +15,24 @@ before do node.config(['spanning-tree mode mstp', 'spanning-tree mst configuration', - 'instance 1 vlans 1', 'exit']) + 'instance 10 vlans 100', 'exit']) end it 'returns the stp instance resource as a hash' do + expect(subject.get('10')).to be_a_kind_of(Hash) + end + + it 'returns the default stp instance resources as a hash' do + expect(subject.get('0')).to be_a_kind_of(Hash) expect(subject.get('1')).to be_a_kind_of(Hash) end it 'returns the instance priority' do + expect(subject.get('10')).to include(:priority) + end + + it 'returns the default instances priority' do + expect(subject.get('0')).to include(:priority) expect(subject.get('1')).to include(:priority) end end @@ -41,38 +51,64 @@ before do node.config(['spanning-tree mode mstp', 'spanning-tree mst configuration', - 'instance 1 vlans 1', 'exit']) + 'instance 1 vlans 1', + 'instance 10 vlans 100', 'exit']) end it 'deletes the mst instance' do + expect(subject.get('10')).not_to be_nil + expect(subject.delete('10')).to be_truthy + expect(subject.get('10')).to be_nil + end + + it 'does not delete the default mst instance' do expect(subject.get('1')).not_to be_nil expect(subject.delete('1')).to be_truthy - expect(subject.get('1')).to be_nil + expect(subject.get('1')).not_to be_nil end end describe '#set_priority' do before do - node.config(['default spanning-tree mst 1 priority', + node.config(['default spanning-tree mst 10 priority', 'spanning-tree mode mstp', 'default spanning-tree mst configuration', 'spanning-tree mst configuration', - 'instance 1 vlans 1', 'exit']) + 'instance 10 vlans 100', 'exit']) end it 'set the instance priority' do + expect(subject.get('10')[:priority]).to eq('32768') + expect(subject.set_priority('10', value: '16384')).to be_truthy + expect(subject.get('10')[:priority]).to eq('16384') + end + + it 'set the default instance priority' do expect(subject.get('1')[:priority]).to eq('32768') expect(subject.set_priority('1', value: '4096')).to be_truthy expect(subject.get('1')[:priority]).to eq('4096') end it 'set the instance priority to default' do + expect(subject.set_priority('10', value: '16384', + default: true)).to be_truthy + expect(subject.get('10')[:priority]).to eq('32768') + end + + it 'set the default instance priority to default' do expect(subject.set_priority('1', value: '4096', default: true)).to be_truthy expect(subject.get('1')[:priority]).to eq('32768') end it 'set the instance priority to enable false' do + expect(subject.set_priority('10', value: '16384', + default: false, + enable: false)).to be_truthy + expect(subject.get('10')[:priority]).to eq('32768') + end + + it 'set the default instance priority to enable false' do expect(subject.set_priority('1', value: '4096', default: false, enable: false)).to be_truthy @@ -80,6 +116,13 @@ end it 'set the instance priority to enable true' do + expect(subject.set_priority('10', value: '16384', + default: false, + enable: true)).to be_truthy + expect(subject.get('10')[:priority]).to eq('16384') + end + + it 'set the default instance priority to enable true' do expect(subject.set_priority('1', value: '4096', default: false, enable: true)).to be_truthy From 4a8b2da1ae1336ef545e1cc014dbb6d92c5db348 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 7 Sep 2016 16:28:48 -0400 Subject: [PATCH 23/60] Restrict json rubygem when testing with Ruby 1.9 --- Gemfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 06c2edb..8d4e4c2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,6 @@ source ENV['GEM_SOURCE'] || 'https://rubygems.org' gem 'inifile' -gem 'json' gem 'net_http_unix' gem 'netaddr' @@ -31,10 +30,12 @@ end # Rubocop > 0.37 requires a gem that only works with ruby 2.x if RUBY_VERSION.to_f < 2.0 + gem 'json', '<2.0' group :development, :test do gem 'rubocop', '>=0.35.1', '< 0.38' end else + gem 'json' group :development, :test do gem 'rubocop', '>=0.35.1' end From 022cf7846193a6a2a47293a8d7389f3a6ca2a27d Mon Sep 17 00:00:00 2001 From: Ruben Knaus Date: Thu, 8 Sep 2016 09:32:59 +0200 Subject: [PATCH 24/60] fix test to reset the priority before the run --- spec/system/rbeapi/api/stp_instances_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/system/rbeapi/api/stp_instances_spec.rb b/spec/system/rbeapi/api/stp_instances_spec.rb index 60cc943..dffb71f 100644 --- a/spec/system/rbeapi/api/stp_instances_spec.rb +++ b/spec/system/rbeapi/api/stp_instances_spec.rb @@ -71,6 +71,7 @@ describe '#set_priority' do before do node.config(['default spanning-tree mst 10 priority', + 'no spanning-tree mst 1 priority', 'spanning-tree mode mstp', 'default spanning-tree mst configuration', 'spanning-tree mst configuration', From da66ce98bbaa14a54debf85f9d793eb7025947a0 Mon Sep 17 00:00:00 2001 From: Florin Vinti Date: Thu, 8 Sep 2016 09:59:09 +0200 Subject: [PATCH 25/60] remove set multicast-group test (redundant) --- spec/system/rbeapi/api/interfaces_base_spec.rb | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/spec/system/rbeapi/api/interfaces_base_spec.rb b/spec/system/rbeapi/api/interfaces_base_spec.rb index 6ea705a..540422d 100644 --- a/spec/system/rbeapi/api/interfaces_base_spec.rb +++ b/spec/system/rbeapi/api/interfaces_base_spec.rb @@ -60,21 +60,7 @@ it 'returns the interface resource' do expect(subject.get('Vxlan1')).to eq(entity) - end - - let(:entity) do - { name: 'Vxlan1', type: 'vxlan', description: '', - shutdown: false, load_interval: '', source_interface: '', multicast_group: '224.0.2.0', - udp_port: 4789, flood_list: [], vlans: {} } - end - - before do - node.config(['no interface Vxlan1', 'interface Vxlan1', 'vxlan multicast-group 224.0.2.0']) - end - - it 'returns the interface resource with multicast group set' do - expect(subject.get('Vxlan1')).to eq(entity) - end + end end end From 0fb04147639bbad602cf7ce1eb11ea100525e579 Mon Sep 17 00:00:00 2001 From: Florin Vinti Date: Thu, 8 Sep 2016 10:03:44 +0200 Subject: [PATCH 26/60] remove whitespace --- spec/system/rbeapi/api/interfaces_base_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/rbeapi/api/interfaces_base_spec.rb b/spec/system/rbeapi/api/interfaces_base_spec.rb index 540422d..2e40911 100644 --- a/spec/system/rbeapi/api/interfaces_base_spec.rb +++ b/spec/system/rbeapi/api/interfaces_base_spec.rb @@ -60,7 +60,7 @@ it 'returns the interface resource' do expect(subject.get('Vxlan1')).to eq(entity) - end + end end end From ca4dc21d90c4e830a10a406de0715cab52dbefdf Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 8 Sep 2016 09:35:07 -0400 Subject: [PATCH 27/60] Sort the portchannel members list --- lib/rbeapi/api/interfaces.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index b004d98..e88b6f5 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -782,7 +782,7 @@ def parse_members(name) grpid = name.scan(/(?<=Port-Channel)\d+/)[0] command = "show port-channel #{grpid} all-ports" config = node.enable(command, encoding: 'text') - values = config.first[:result]['output'].scan(/\bEthernet[^\s]+/) + values = config.first[:result]['output'].scan(/\bEthernet[^\s]+/).sort { members: values } end private :parse_members From e0ebc168e6135fcdba217cb5bd32359d9dc44f8a Mon Sep 17 00:00:00 2001 From: John Corbin Date: Fri, 12 Feb 2016 15:34:47 -0800 Subject: [PATCH 28/60] Added support for switchconfigs. --- lib/rbeapi/switchconfig.rb | 351 ++++++++++++++++++ .../matchers/switch_config_sections.rb | 80 ++++ spec/unit/rbeapi/switchconfig2_spec.rb | 119 ++++++ spec/unit/rbeapi/switchconfig3_spec.rb | 153 ++++++++ spec/unit/rbeapi/switchconfig_spec.rb | 212 +++++++++++ 5 files changed, 915 insertions(+) create mode 100644 lib/rbeapi/switchconfig.rb create mode 100644 spec/support/matchers/switch_config_sections.rb create mode 100644 spec/unit/rbeapi/switchconfig2_spec.rb create mode 100644 spec/unit/rbeapi/switchconfig3_spec.rb create mode 100644 spec/unit/rbeapi/switchconfig_spec.rb diff --git a/lib/rbeapi/switchconfig.rb b/lib/rbeapi/switchconfig.rb new file mode 100644 index 0000000..86f2993 --- /dev/null +++ b/lib/rbeapi/switchconfig.rb @@ -0,0 +1,351 @@ +# +# Copyright (c) 2016, Arista Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Arista Networks nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +## +# Rbeapi toplevel namespace +module Rbeapi + ## + # Rbeapi::SwitchConfig + module SwitchConfig + ## + # Section class + # + # XXX: Is this the right doc format for a class and accessors? + # + # A switch configuration section consists of the command line that + # enters into the configuration mode, an array of command strings + # that are executed in the current configuration mode, a reference + # to the parent section, and an array of refereces to all sub-sections + # contained within this section. A sub-section is a nested configuration + # mode. + # + # Read Accessors for following class instance variables: + # line: , + # parent:
, + # cmds: array, + # children: array
+ # + class Section + attr_reader :line + attr_reader :parent + attr_reader :cmds + attr_reader :children + + ## + # The Section class contains a parsed section of switch config. + # + # @param config [String] A string containing the switch configuration. + # + # @return [Section] Returns an instance of Section + + def initialize(line, parent) + @line = line + @parent = parent + @cmds = [] + @children = [] + end + + ## + # Add a child to the end of the children array. + # + # @param child [Section] A Section class instance. + def add_child(child) + @children.push(child) + end + + ## + # Add a cmd to the end of the cmds array if it is not already in + # the cmd array. + # + # @param cmd [String] A command string that is added to the cmds array. + def add_cmd(cmd) + @cmds.push(cmd) unless @cmds.include?(cmd) + end + + ## + # Return the child that has the specified line (command mode). + # + # @param line [String] The mode command for this section. + def get_child(line) + @children.each do |child| + return child if child.line == line + end + nil + end + + ## + # Prepend the word 'default' to a cmd. + # + # @param cmd [String] A command string + # + # @return [String] Returns command string with word 'default' prepended. + def prepend_default(cmd) + # Return if the command is prepended by a default + return cmd unless cmd.scan(/^\s*default\s+/).empty? + # If the command is prepended by a no, then remove it. + new_cmd = cmd.sub(/^(\s*)(no\s+)/, '\1') + new_cmd.sub(/^(?\s*)/, '\kdefault ') + end + + ## + # Generates an array of commands for the current section. If the + # add_default option is set then each command is prepended with the + # word 'default'. Commands that enter a mode are not prepended with + # the word 'default'. Performs recursive calls to process children. + # + # @param opts [Hash] the options to create a message with. + # + # @option opts add_default [Boolean] Set to true to have commands + # prepended with the word 'default'. Default is false. + # + # @return [Array] Returns an array of commands that can be + # sent to a switch. + def gen_commands(opts = {}) + add_default = opts.fetch(:add_default, false) + + # Iterate over the commands, if the command has an associated + # child then process the child. This will preserve the order of + # the configuration. + ret_cmds = [] + cmds.each do |cmd| + child = get_child(cmd) + cmd = prepend_default(cmd) if add_default && !child + ret_cmds.push(cmd) + next unless child + child_cmds = child.gen_commands(opts) + next unless child_cmds.length > 0 + ret_cmds.push(child_cmds) + ret_cmds.flatten! + end + ret_cmds + end + + ## + # Private campare method to compare the commands between two Section + # classes. + # + # @param cmds2 [Array] An array of commands. + # + # @return [Array] The array of commands in @cmds that are not + # in cmds2. The array is empty if @cmds equals cmds2. + def _compare_cmds(cmds2) + c1 = Set.new(@cmds) + c2 = Set.new(cmds2) + # Compare the commands and return the difference as an array of strings + c1.difference(c2).to_a + end + private :_compare_cmds + + ## + # Campare method to compare two Section classes. + # The comparison will recurse through all the children in the Sections. + # The parent is ignored at the top level section. Only call this + # method if self and section2 have the same line. + # + # @param section2 [Section] An instance of a Section class to compare. + # + # @return [Section] The Section object contains the portion of self + # that is not in section2. + def compare_r(section2) + fail '@line must equal section2.line' if @line != section2.line + + # XXX Need to have a list of exceptions of mode commands that + # support default. If all the commands have been removed from + # that section in the new config then the old config just wants + # to default the mode command. + # ex: spanning-tree mst configuration + # instance 1 vlan 1 + # Currently generates this error: + # ' default instance 1 vlan 1' failed: invalid command + + results = Section.new(@line, nil) + + # Compare the commands + diff_cmds = _compare_cmds(section2.cmds) + diff_cmds.each do |cmd| + results.add_cmd(cmd) + end + + # Using a depth first search to recursively descend through the + # children doing a comparison. + @children.each do |s1_child| + s2_child = section2.get_child(s1_child.line) + if s2_child + # Sections Match based on the line. Compare the children + # and if there are differences add them to the results. + res = s1_child.compare_r(s2_child) + if !res.children.empty? || !res.cmds.empty? + results.add_child(res) + results.add_cmd(s1_child.line) + end + else + # Section 1 has child, but section 2 does not, add to results + results.add_child(s1_child.clone) + results.add_cmd(s1_child.line) + end + end + + results + end + + ## + # Campare a Section class to the current section. + # The comparison will recurse through all the children in the Sections. + # The parent is ignored at the top level section. + # + # @param section2 [Section] An instance of a Section class to compare. + # + # @return [Array
] Returns an array of 2 Section objects. The + # first Section object contains the portion of self that is not + # in section2. The second Section object returned is the portion of + # section2 that is not in self. + def compare(section2) + if @line != section2.line + fail 'XXX What if @line does not equal section2.line' + end + + results = [] + # Compare self with section2 + results[0] = compare_r(section2) + # Compare section2 with self + results[1] = section2.compare_r(self) + results + end + end + + ## + # SwitchConfig class + class SwitchConfig + attr_accessor :name + attr_reader :global + + ## + # The SwitchConfig class will parse a string containing a switch + # configuration and return an instance of a SwitchConfig. The + # SwitchConfig contains the global section which contains + # references to all sub-sections (children). + # + # { + # name: , + # global:
, + # } + # + # @param config [String] A string containing the switch configuration. + # + # @return [Section] Returns an instance of Section + # XXX Name is not really used - can delete + def initialize(name, config) + @name = name + @indent = 3 + chk_format(config) + parse(config) + end + + ## + # Check format on a switch configuration string. + # + # Verify that the indentation is correct on the switch configuration. + # + # @param config [String] A string containing the switch configuration. + # + # @return [boolean] Returns true if format is good, otherwise raises + # an argument error. + def chk_format(config) + config.each_line do |line| + ind = line[/\A */].size + if ind % @indent != 0 + fail ArgumentError, 'SwitchConfig indentation must be multiple of '\ + "#{@indent} improper indent #{ind}: #{line}" + end + end + true + end + private :chk_format + + ## + # Parse a switch configuration into sections. + # + # Parse a switch configuration and return a Config class. + # A switch configuration consists of the global section that contains + # a reference to all switch configuration sub-sections (children). + # Lines starting with '!' (comments) are ignored + # + # @param config [String] A string containing the switch configuration. + def parse(config) + # Setup global section + section = Section.new('', nil) + @global = section + + prev_indent = 0 + prev_line = '' + config.each_line do |line| + # Ignore comment lines and the end statement if there + # XXX Fix parsing end + next if line.start_with?('!') || line.start_with?('end') + line.chomp! + indent_level = line[/\A */].size / @indent + if indent_level > prev_indent + # New section + section = Section.new(prev_line, section) + section.parent.add_child(section) + prev_indent = indent_level + elsif indent_level < prev_indent + # XXX This has a bug if we pop more than one section + # XXX Bug if we have 2 subsections with intervening commands + # End of current section + section = section.parent + prev_indent = indent_level + end + # Add the line to the current section + section.add_cmd(line) + prev_line = line + end + end + private :parse + + ## + # Campare the current SwitchConfig class with another SwitchConfig class. + # + # @param switch_config [SwitchConfig] An instance of a SwitchConfig + # class to compare with the current instance. + # + # @return [Array] Returns an array of 2 Section objects. The + # first Section object contains the portion of the current + # SwitchConfig instance that is not in the passed in switch_config. The + # second Section object is the portion of the passed in switch_config + # that is not in the current SwitchConfig instance. + def compare(switch_config) + @global.compare(switch_config.global) + end + end + end +end diff --git a/spec/support/matchers/switch_config_sections.rb b/spec/support/matchers/switch_config_sections.rb new file mode 100644 index 0000000..c940ebc --- /dev/null +++ b/spec/support/matchers/switch_config_sections.rb @@ -0,0 +1,80 @@ +# +# Copyright (c) 2016, Arista Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Arista Networks nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +def get_child(section, line) + section.children.each do |child| + return child if child.line == line + end + nil +end + +def section_compare(section1, section2) + # Verify lines are the same + return false unless section1.line == section2.line + + # Verify cmds are the same + c1 = Set.new(section1.cmds) + c2 = Set.new(section2.cmds) + return false unless c1 == c2 + + # Return false if the number of children are different + return false unless section1.children.length == section2.children.length + + # Using a depth first search to recursively descend through the + # children doing a comparison. + section1.children.each do |s1_child| + s2_child = get_child(section2, s1_child.line) + return false unless s2_child + return false unless section_compare(s1_child, s2_child) + end + true +end + +RSpec::Matchers.define :section_equal do |expected| + if expected.class != Rbeapi::SwitchConfig::Section + fail 'expected is not a Rbeapi::SwitchConfig::Section class' + end + + match do |actual| + if actual.class != Rbeapi::SwitchConfig::Section + fail 'actual is not a Rbeapi::SwitchConfig::Section class' + end + + section_compare(actual, expected) + end + + description do + 'Verifies contents of section with a deep class comparison.' + end + + diffable +end diff --git a/spec/unit/rbeapi/switchconfig2_spec.rb b/spec/unit/rbeapi/switchconfig2_spec.rb new file mode 100644 index 0000000..4d3eb0e --- /dev/null +++ b/spec/unit/rbeapi/switchconfig2_spec.rb @@ -0,0 +1,119 @@ +# +# Copyright (c) 2016, Arista Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Arista Networks nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +require 'spec_helper' + +require 'rbeapi/switchconfig' + +include FixtureHelpers +include Rbeapi::SwitchConfig + +describe Rbeapi::SwitchConfig::SwitchConfig do + test_config = <<-EOS +! Test on multi-level children sections +management api http-commands + no shutdown + vrf cloud-mgmt + no shutdown +EOS + test_config_global = ['management api http-commands'] + cmds = [[' no shutdown', + ' vrf cloud-mgmt'], + [' no shutdown']] + + subject { described_class.new('test', test_config) } + + # SwitchConfig class methods + describe '#initialize' do + it 'returns the processed configuration' do + sc = subject.global + # Validate the global section + expect(sc.line).to eq('') + expect(sc.parent).to eq(nil) + expect(sc.cmds).to eq(test_config_global) + expect(sc.children.length).to eq(1) + + # Validate the child of global + expect(sc.children[0].line).to eq(test_config_global[0]) + expect(sc.children[0].parent).to eq(sc) + expect(sc.children[0].cmds).to eq(cmds[0]) + expect(sc.children[0].children.length).to eq(1) + + # Validate the child of global + child = sc.children[0].children + expect(child[0].line).to eq(cmds[0][1]) + expect(child[0].parent).to eq(sc.children[0]) + expect(child[0].cmds).to eq(cmds[1]) + expect(child[0].children.length).to eq(0) + end + end + + describe '#compare' do + it 'Verify compare returns array of 2 Sections' do + expect(subject.compare(subject)).to be_instance_of(Array) + expect(subject.compare(subject)[0]).to be_instance_of(Section) + expect(subject.compare(subject)[1]).to be_instance_of(Section) + end + + it 'Verify compare of same switch configs' do + expect(subject.compare(subject)[0].line).to eq('') + expect(subject.compare(subject)[0].cmds).to eq([]) + expect(subject.compare(subject)[0].children).to eq([]) + expect(subject.compare(subject)[1].line).to eq('') + expect(subject.compare(subject)[1].cmds).to eq([]) + expect(subject.compare(subject)[1].children).to eq([]) + end + + it 'Verify compare of shutdown management vrf' do + new_conf = <<-EOS +management api http-commands + no shutdown + vrf cloud-mgmt + shutdown +EOS + org_new_diff = <<-EOS +management api http-commands + vrf cloud-mgmt + no shutdown +EOS + new_org_diff = <<-EOS +management api http-commands + vrf cloud-mgmt + shutdown +EOS + swc_new = Rbeapi::SwitchConfig::SwitchConfig.new('', new_conf) + swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new('', org_new_diff) + swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new('', new_org_diff) + expect(subject.compare(swc_new)[0]).to section_equal(swc_org_new.global) + expect(subject.compare(swc_new)[1]).to section_equal(swc_new_org.global) + end + end +end diff --git a/spec/unit/rbeapi/switchconfig3_spec.rb b/spec/unit/rbeapi/switchconfig3_spec.rb new file mode 100644 index 0000000..f1b704a --- /dev/null +++ b/spec/unit/rbeapi/switchconfig3_spec.rb @@ -0,0 +1,153 @@ +# +# Copyright (c) 2016, Arista Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Arista Networks nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +require 'spec_helper' + +require 'rbeapi/switchconfig' + +include FixtureHelpers +include Rbeapi::SwitchConfig + +describe Rbeapi::SwitchConfig::SwitchConfig do + test_config = <<-EOS +! Test on multi-level children sections +! Test with negated commands +no snmp-server enable traps bgp +management api http-commands + no shutdown + vrf cloud-mgmt + no shutdown +! +end +EOS + test_config_global = ['no snmp-server enable traps bgp', + 'management api http-commands'] + cmds = [[' no shutdown', + ' vrf cloud-mgmt'], + [' no shutdown']] + + subject { described_class.new('test', test_config) } + + # SwitchConfig class methods + describe '#initialize' do + it 'returns the processed configuration' do + sc = subject.global + # Validate the global section + expect(sc.line).to eq('') + expect(sc.parent).to eq(nil) + expect(sc.cmds).to eq(test_config_global) + expect(sc.children.length).to eq(1) + + # Validate the child of global + expect(sc.children[0].line).to eq(test_config_global[1]) + expect(sc.children[0].parent).to eq(sc) + expect(sc.children[0].cmds).to eq(cmds[0]) + expect(sc.children[0].children.length).to eq(1) + + # Validate the child of global + child = sc.children[0].children + expect(child[0].line).to eq(cmds[0][1]) + expect(child[0].parent).to eq(sc.children[0]) + expect(child[0].cmds).to eq(cmds[1]) + expect(child[0].children.length).to eq(0) + end + end + + describe '#compare' do + it 'Verify compare returns array of 2 Sections' do + expect(subject.compare(subject)).to be_instance_of(Array) + expect(subject.compare(subject)[0]).to be_instance_of(Section) + expect(subject.compare(subject)[1]).to be_instance_of(Section) + end + + it 'Verify compare of same switch configs' do + expect(subject.compare(subject)[0].line).to eq('') + expect(subject.compare(subject)[0].cmds).to eq([]) + expect(subject.compare(subject)[0].children).to eq([]) + expect(subject.compare(subject)[1].line).to eq('') + expect(subject.compare(subject)[1].cmds).to eq([]) + expect(subject.compare(subject)[1].children).to eq([]) + end + + it 'Verify compare of shutdown management vrf' do + new_conf = <<-EOS +management api http-commands + no shutdown + vrf cloud-mgmt + shutdown +EOS + org_new_diff = <<-EOS +no snmp-server enable traps bgp +management api http-commands + vrf cloud-mgmt + no shutdown +EOS + new_org_diff = <<-EOS +management api http-commands + vrf cloud-mgmt + shutdown +EOS + swc_new = Rbeapi::SwitchConfig::SwitchConfig.new('', new_conf) + swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new('', org_new_diff) + swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new('', new_org_diff) + expect(subject.compare(swc_new)[0]).to section_equal(swc_org_new.global) + expect(subject.compare(swc_new)[1]).to section_equal(swc_new_org.global) + end + end + + # Section class methods + describe 'Section Class' do + describe '#gen_commands' do + conf = <<-EOS +no snmp-server enable traps bgp +management api http-commands + no shutdown + vrf cloud-mgmt + no shutdown +EOS + conf_array = conf.split("\n") + default_conf = <<-EOS +default snmp-server enable traps bgp +management api http-commands + default shutdown + vrf cloud-mgmt + default shutdown +EOS + default_array = default_conf.split("\n") + it 'Verify command correctly generated' do + swc = Rbeapi::SwitchConfig::SwitchConfig.new('', conf) + sc = swc.global + expect(sc.gen_commands).to eq(conf_array) + expect(sc.gen_commands(add_default: true)).to eq(default_array) + end + end + end +end diff --git a/spec/unit/rbeapi/switchconfig_spec.rb b/spec/unit/rbeapi/switchconfig_spec.rb new file mode 100644 index 0000000..4116919 --- /dev/null +++ b/spec/unit/rbeapi/switchconfig_spec.rb @@ -0,0 +1,212 @@ +# +# Copyright (c) 2016, Arista Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Arista Networks nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +require 'spec_helper' + +require 'rbeapi/switchconfig' + +include FixtureHelpers +include Rbeapi::SwitchConfig + +describe Rbeapi::SwitchConfig::SwitchConfig do + test_config = <<-EOS +! Config Description Comment +vlan 100 +! +interface Ethernet 2 + switchport mode trunk + switchport trunk allowed vlan 100,200 +! +EOS + test_config_global = ['vlan 100', 'interface Ethernet 2'] + cmds = [' switchport mode trunk', + ' switchport trunk allowed vlan 100,200'] + + bad_indent = <<-EOS +! Vxlan without CVX +vlan 100 +interface Ethernet 1 + switchport access vlan 100 +! +EOS + + subject { described_class.new('test', test_config) } + + # SwitchConfig class methods + describe '#initialize' do + it 'returns the processed configuration' do + sc = subject.global + # Validate the global section + expect(sc).to be_instance_of(Section) + expect(sc.line).to eq('') + expect(sc.parent).to eq(nil) + expect(sc.cmds).to eq(test_config_global) + expect(sc.children.length).to eq(1) + + # Validate the children of global + expect(sc.children[0].line).to eq(test_config_global[1]) + expect(sc.children[0].parent).to eq(sc) + expect(sc.children[0].cmds).to eq(cmds) + expect(sc.children[0].children.length).to eq(0) + end + + it 'returns error for invalid indentation' do + expect \ + { Rbeapi::SwitchConfig::SwitchConfig.new('bad_indent', bad_indent) }.to\ + raise_error ArgumentError + end + end + + describe '#compare' do + it 'Verify compare returns array of 2 Sections' do + expect(subject.compare(subject)).to be_instance_of(Array) + expect(subject.compare(subject)[0]).to be_instance_of(Section) + expect(subject.compare(subject)[1]).to be_instance_of(Section) + end + + it 'Verify compare of same switch configs' do + expect(subject.compare(subject)[0].line).to eq('') + expect(subject.compare(subject)[0].cmds).to eq([]) + expect(subject.compare(subject)[0].children).to eq([]) + expect(subject.compare(subject)[1].line).to eq('') + expect(subject.compare(subject)[1].cmds).to eq([]) + expect(subject.compare(subject)[1].children).to eq([]) + end + + it 'Verify compare of same switch configs without comment' do + conf = <<-EOS +vlan 100 +interface Ethernet 2 + switchport mode trunk + switchport trunk allowed vlan 100,200 +EOS + sw_config = Rbeapi::SwitchConfig::SwitchConfig.new('', conf) + expect(subject.compare(sw_config)[0].line).to eq('') + expect(subject.compare(sw_config)[0].cmds).to eq([]) + expect(subject.compare(sw_config)[0].children).to eq([]) + expect(subject.compare(sw_config)[1].line).to eq('') + expect(subject.compare(sw_config)[1].cmds).to eq([]) + expect(subject.compare(sw_config)[1].children).to eq([]) + end + + it 'Verify compare of different vlan id' do + new_conf = <<-EOS +vlan 101 +interface Ethernet 2 + switchport mode trunk + switchport trunk allowed vlan 101,200 +EOS + org_new_diff = <<-EOS +vlan 100 +interface Ethernet 2 + switchport trunk allowed vlan 100,200 +EOS + new_org_diff = <<-EOS +vlan 101 +interface Ethernet 2 + switchport trunk allowed vlan 101,200 +EOS + swc_new = Rbeapi::SwitchConfig::SwitchConfig.new('', new_conf) + swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new('', org_new_diff) + swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new('', new_org_diff) + expect(subject.compare(swc_new)[0]).to section_equal(swc_org_new.global) + expect(subject.compare(swc_new)[1]).to section_equal(swc_new_org.global) + end + end + + # Section class methods + describe 'Section Class' do + parent = Rbeapi::SwitchConfig::Section.new('parent line', nil) + child = Rbeapi::SwitchConfig::Section.new('child line', parent) + + describe '#initialize' do + it 'Verify section intialization' do + expect(child).to be_instance_of(Section) + expect(child.line).to be_instance_of(String) + expect(child.line).to eq('child line') + expect(child.parent).to be_instance_of(Section) + expect(child.parent).to eq(parent) + expect(child.cmds).to be_instance_of(Array) + expect(child.cmds).to be_empty + expect(child.children).to be_instance_of(Array) + expect(child.children).to be_empty + end + end + + describe '#add_child' do + it 'Verify child added to section' do + parent.add_child(child) + expect(parent.children.length).to eq(1) + expect(parent.children[0]).to eq(child) + end + end + + describe '#add_cmd' do + it 'Verify command added to section' do + parent.add_cmd('new command') + expect(parent.cmds.length).to eq(1) + expect(parent.cmds[0]).to eq('new command') + end + end + + describe '#get_child' do + it 'Verify child returned from section' do + parent.add_child(child) + expect(parent.get_child('child line')).to eq(child) + end + end + + describe '#gen_commands' do + conf = <<-EOS +vlan 101 +interface Ethernet 2 + switchport mode trunk + switchport trunk allowed vlan 101,200 +vlan 102 +EOS + conf_array = conf.split("\n") + default_conf = <<-EOS +default vlan 101 +interface Ethernet 2 + default switchport mode trunk + default switchport trunk allowed vlan 101,200 +default vlan 102 +EOS + default_array = default_conf.split("\n") + it 'Verify command correctly generated' do + swc = Rbeapi::SwitchConfig::SwitchConfig.new('', conf) + sc = swc.global + expect(sc.gen_commands).to eq(conf_array) + expect(sc.gen_commands(add_default: true)).to eq(default_array) + end + end + end +end From bcc3e261068785b32845ca4b0d14156bb1a46065 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 25 May 2016 10:05:52 -0400 Subject: [PATCH 29/60] Add chef rpms and swix Conflicts: Rakefile gems/inifile/inifile.spec.tmpl gems/net_http_unix/net_http_unix.spec.tmpl gems/netaddr/netaddr.spec.tmpl --- Rakefile | 42 +++++++++++++--------- gems/inifile/inifile.spec.tmpl | 26 +++++++++++++- gems/net_http_unix/net_http_unix.spec.tmpl | 25 ++++++++++++- gems/netaddr/netaddr.spec.tmpl | 27 ++++++++++++-- rbeapi.spec.tmpl | 24 ++++++++++++- 5 files changed, 122 insertions(+), 22 deletions(-) diff --git a/Rakefile b/Rakefile index 9998faf..d49ea27 100644 --- a/Rakefile +++ b/Rakefile @@ -13,7 +13,8 @@ RPM_OPTS = '--define "_topdir %(pwd)/rpmbuild" --define "_builddir ' \ desc 'Generate regular and puppet-enterprise rbeapi RPMs for EOS' task rpm: :build do system "sed -e 's/^Version:.*/Version: #{Rbeapi::VERSION}/g' " \ - 'rbeapi.spec.tmpl > rbeapi.spec' + 'rbeapi-chef.spec.tmpl > rbeapi.spec' + # 'rbeapi.spec.tmpl > rbeapi.spec' system "rpmbuild #{RPM_OPTS} rbeapi.spec" RPMS = `find rpms/noarch -name "*rbeapi*rpm"` puts "\n################################################\n#" @@ -82,26 +83,33 @@ task all_rpms: :build do puts 'RPMs are available in rpms/noarch/' puts "Copy the RPMs to an EOS device then run the 'swix create' command." puts ' Examples: ' + puts ' Chef client: ' + puts ' cd /mnt/flash; \\' + puts " swix create rbeapi-chef-#{Rbeapi::VERSION}-2.swix \\" + puts " rubygem-rbeapi-chef-#{Rbeapi::VERSION}-2.eos4.noarch.rpm \\" + puts ' rubygem-inifile-chef-3.0.0-5.eos4.noarch.rpm \\' + puts ' rubygem-netaddr-chef-1.5.1-4.eos4.noarch.rpm \\' + puts ' rubygem-net_http_unix-0.2.1-5.eos4.noarch.rpm' puts ' Puppet Open Source: ' puts ' cd /mnt/flash; \\' puts " swix create rbeapi-#{Rbeapi::VERSION}-1.swix \\" puts " rubygem-rbeapi-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" - puts ' rubygem-inifile-3.0.0-4.eos4.noarch.rpm \\' - puts ' rubygem-netaddr-1.5.1-3.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-0.2.1-4.eos4.noarch.rpm' + puts ' rubygem-inifile-3.0.0-5.eos4.noarch.rpm \\' + puts ' rubygem-netaddr-1.5.1-4.eos4.noarch.rpm \\' + puts ' rubygem-net_http_unix-0.2.1-5.eos4.noarch.rpm' puts ' Puppet-enterprise agent (3.x): ' puts ' cd/mnt/flash; \\' puts " swix create rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix \\" puts " rubygem-rbeapi-puppet3-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" - puts ' rubygem-inifile-puppet3-3.0.0-4.eos4.noarch.rpm \\' - puts ' rubygem-netaddr-puppet3-1.5.1-3.eos4.noarch.rpm' + puts ' rubygem-inifile-puppet3-3.0.0-5.eos4.noarch.rpm \\' + puts ' rubygem-netaddr-puppet3-1.5.1-4.eos4.noarch.rpm' puts ' Puppet-All-in-one agent (2015.x/4.x): ' puts ' cd/mnt/flash; \\' puts " swix create rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.swix \\" puts " rubygem-rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" - puts ' rubygem-inifile-puppet-aio-3.0.0-4.eos4.noarch.rpm \\' - puts ' rubygem-netaddr-puppet-aio-1.5.1-3.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-puppet-aio-0.2.1-4.eos4.noarch.rpm' + puts ' rubygem-inifile-puppet-aio-3.0.0-5.eos4.noarch.rpm \\' + puts ' rubygem-netaddr-puppet-aio-1.5.1-4.eos4.noarch.rpm \\' + puts ' rubygem-net_http_unix-puppet-aio-0.2.1-5.eos4.noarch.rpm' end desc 'Generate SWIX files from RPMs' @@ -112,22 +120,22 @@ task swix: :all_rpms do rm -f rbeapi-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-#{Rbeapi::VERSION}-1.swix \ rubygem-rbeapi-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ - rubygem-inifile-3.0.0-4.eos4.noarch.rpm \ - rubygem-netaddr-1.5.1-3.eos4.noarch.rpm \ - rubygem-net_http_unix-0.2.1-4.eos4.noarch.rpm)" + rubygem-inifile-3.0.0-5.eos4.noarch.rpm \ + rubygem-netaddr-1.5.1-4.eos4.noarch.rpm \ + rubygem-net_http_unix-0.2.1-5.eos4.noarch.rpm)" system "(cd rpms/noarch; rm -f rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix \ rubygem-rbeapi-puppet3-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ - rubygem-inifile-puppet3-3.0.0-4.eos4.noarch.rpm \ - rubygem-netaddr-puppet3-1.5.1-3.eos4.noarch.rpm)" + rubygem-inifile-puppet3-3.0.0-5.eos4.noarch.rpm \ + rubygem-netaddr-puppet3-1.5.1-4.eos4.noarch.rpm)" system "(cd rpms/noarch; rm -f rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.swix \ rubygem-rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ - rubygem-inifile-puppet-aio-3.0.0-4.eos4.noarch.rpm \ - rubygem-netaddr-puppet-aio-1.5.1-3.eos4.noarch.rpm \ - rubygem-net_http_unix-puppet-aio-0.2.1-4.eos4.noarch.rpm)" + rubygem-inifile-puppet-aio-3.0.0-5.eos4.noarch.rpm \ + rubygem-netaddr-puppet-aio-1.5.1-4.eos4.noarch.rpm \ + rubygem-net_http_unix-puppet-aio-0.2.1-5.eos4.noarch.rpm)" SWIXS = `find rpms/noarch -name "rbeapi*swix" -ls` puts "\n################################################\n#" puts "The following artifacts are in rpms/noarch/\n#{SWIXS}" diff --git a/gems/inifile/inifile.spec.tmpl b/gems/inifile/inifile.spec.tmpl index a49e932..057c131 100644 --- a/gems/inifile/inifile.spec.tmpl +++ b/gems/inifile/inifile.spec.tmpl @@ -3,7 +3,7 @@ Name: %{?enterprise:pe-}rubygem-%{gem_name} Version: 3.0.0 -Release: 4.eos4 +Release: 5.eos4 Summary: INI file reader and writer Group: Development/Languages @@ -49,6 +49,15 @@ are also possible var1 = baz var2 = shoodle. +%package chef +Summary: Inifile rubygem packaged for Chef +Group: Development/Languages +Requires: chef +Provides: cehf-rubygem(%{gem_name}) = %{version} +Provides: cehf-rubygem-%{gem_name} = %{version} +%description chef +The inifile rubygem packaged for Chef client on Arista EOS. + %package puppet3 Summary: Inifile rubygem packaged for Puppet 3.x on Arista EOS Group: Development/Languages @@ -78,6 +87,9 @@ install %{SOURCE0} %{buildroot}/ %files /%{gem_name}-%{version}.gem +%files chef +/%{gem_name}-%{version}.gem + %files puppet3 /%{gem_name}-%{version}.gem @@ -91,6 +103,15 @@ gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 +%post chef +GEM=/opt/chef/embedded/bin/gem +GEM_OPTS="--no-document --local" +${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 + +%preun chef +GEM=/opt/chef/enbedded/bin/gem +${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 + %post puppet3 GEM=/opt/puppet/bin/gem GEM_OPTS="--no-rdoc --no-ri --local" @@ -110,6 +131,9 @@ GEM=/opt/puppetlabs/puppet/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog +* Tue May 24 2016 Jere Julian - 3.0.0-5 +- Add chef package + * Wed Apr 6 2016 Jere Julian - 3.0.0-4 - Disable install of gem docs diff --git a/gems/net_http_unix/net_http_unix.spec.tmpl b/gems/net_http_unix/net_http_unix.spec.tmpl index 18cacf4..39471e7 100644 --- a/gems/net_http_unix/net_http_unix.spec.tmpl +++ b/gems/net_http_unix/net_http_unix.spec.tmpl @@ -3,7 +3,7 @@ Name: %{?enterprise:pe-}rubygem-%{gem_name} Version: 0.2.1 -Release: 4.eos4 +Release: 5.eos4 Summary: Wrapper around Net::HTTP with AF_UNIX support Group: Development/Languages @@ -19,6 +19,14 @@ BuildArch: noarch %description Wrapper around Net::HTTP with AF_UNIX support. +%package chef +Group: Development/Languages +Summary: Net_http_unix rubygem packaged for Chef client +Requires: chef +Provides: chef(%{gem_name}) = %{version} +Provides: chef%{gem_name} = %{version} +%description chef + %package puppet3 Group: Development/Languages Summary: Net_http_unix rubygem packaged for Puppet Enterprise 3.x agents @@ -45,6 +53,9 @@ install %{SOURCE0} %{buildroot}/ %files /%{gem_name}-%{version}.gem +%files chef +/%{gem_name}-%{version}.gem + %files puppet3 /%{gem_name}-%{version}.gem @@ -58,6 +69,15 @@ gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 +%post chef +GEM=/opt/chef/embedded/bin/gem +GEM_OPTS="--no-document --local" +${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 + +%preun chef +GEM=/opt/chef/embedded/bin/gem +${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 + %post puppet3 GEM=/opt/puppet/bin/gem GEM_OPTS="--no-rdoc --no-ri --local" @@ -77,6 +97,9 @@ GEM=/opt/puppetlabs/puppet/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog +* Tue May 24 2016 Jere Julian - 0.2.1-5 +- Add Chef package + * Wed Apr 6 2016 Jere Julian - 0.2.1-4 - Disable install of gem docs diff --git a/gems/netaddr/netaddr.spec.tmpl b/gems/netaddr/netaddr.spec.tmpl index 594ae1d..71c1d4c 100644 --- a/gems/netaddr/netaddr.spec.tmpl +++ b/gems/netaddr/netaddr.spec.tmpl @@ -2,8 +2,8 @@ %global gem_name netaddr Name: %{?enterprise:pe-}rubygem-%{gem_name} -Version: 1.5.0 -Release: 3.eos4 +Version: 1.5.1 +Release: 4.eos4 Summary: A package for manipulating network addresses Group: Development/Languages License: Unknown @@ -18,6 +18,14 @@ BuildArch: noarch %description A package for manipulating network addresses. +%package chef +Summary: NetAddr rubygem packaged for Chef client +Group: Development/Languages +Requires: chef +Provides: chef-rubygem(%{gem_name}) = %{version} +Provides: chef-rubygem-%{gem_name} = %{version} +%description chef + %package puppet3 Summary: NetAddr rubygem packaged for Puppet Enterprise 3.x agents Group: Development/Languages @@ -44,6 +52,9 @@ install %{SOURCE0} %{buildroot}/ %files /%{gem_name}-%{version}.gem +%files chef +/%{gem_name}-%{version}.gem + %files puppet3 /%{gem_name}-%{version}.gem @@ -57,6 +68,15 @@ gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 +%post chef +GEM=/opt/chef/embedded/bin/gem +GEM_OPTS="--no-document --local" +${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 + +%preun chef +GEM=/opt/chef/ebmedded/bin/gem +${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 + %post puppet3 GEM=/opt/puppet/bin/gem GEM_OPTS="--no-rdoc --no-ri --local" @@ -76,6 +96,9 @@ GEM=/opt/puppetlabs/puppet/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog +* Tue May 24 2016 Jere Julian - 1.5.1-4 +- Add Chef package + * Wed Apr 6 2016 Jere Julian - 1.5.0-3 - Disable install of gem docs diff --git a/rbeapi.spec.tmpl b/rbeapi.spec.tmpl index d3d1840..5d08b7d 100644 --- a/rbeapi.spec.tmpl +++ b/rbeapi.spec.tmpl @@ -3,7 +3,7 @@ Name: %{?enterprise:pe-}rubygem-%{gem_name} Version: REPLACEME -Release: 1.eos4 +Release: 2.eos4 Summary: Arista eAPI Ruby Library for the EOS command API Group: Development/Languages @@ -31,6 +31,13 @@ The library is freely provided to the open source community for building robust applications using Arista EOS eAPI. Support is provided as best effort through Github iusses. +%package chef +Summary: Arista eAPI Ruby Library for Chef clients +Group: Development/Languages +Requires: chef +%description chef +The Ruby eAPI Client for Chef clients + %package puppet3 Summary: Arista eAPI Ruby Library Puppet Enterprise 3.x agents Group: Development/Languages @@ -66,6 +73,9 @@ install %{SOURCE0} %{buildroot}/ %files /%{gem_name}-%{version}.gem +%files chef +/%{gem_name}-%{version}.gem + %files puppet3 /%{gem_name}-%{version}.gem @@ -79,6 +89,15 @@ gem install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun gem uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 +%post chef +GEM=/opt/chef/embedded/bin/gem +GEM_OPTS="--no-document --local" +${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 + +%preun chef +GEM=/opt/chef/embedded/bin/gem +${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 + %post puppet3 GEM=/opt/puppet/bin/gem GEM_OPTS="--no-rdoc --no-ri --local" @@ -98,6 +117,9 @@ GEM=/opt/puppetlabs/puppet/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog +* Tue May 24 2016 Jere Julian - 0.4.0-2 +- Add Chef sub-package + * Fri Oct 30 2015 Jere Julian - 0.4.0-1 - Detect the location of the puppet-agent's gem install From 9375e007d5ce1d6a85126b772fc8b15009f442d8 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Tue, 31 May 2016 14:54:23 -0400 Subject: [PATCH 30/60] Skip empty lines when parsing config --- lib/rbeapi/switchconfig.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/rbeapi/switchconfig.rb b/lib/rbeapi/switchconfig.rb index 86f2993..e4445e0 100644 --- a/lib/rbeapi/switchconfig.rb +++ b/lib/rbeapi/switchconfig.rb @@ -312,6 +312,7 @@ def parse(config) # XXX Fix parsing end next if line.start_with?('!') || line.start_with?('end') line.chomp! + next if line.empty? indent_level = line[/\A */].size / @indent if indent_level > prev_indent # New section From e61d2fe3be2800059689e3aac15e987a431d4c19 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Tue, 31 May 2016 14:57:43 -0400 Subject: [PATCH 31/60] Correct typo in chef swix instructions Conflicts: Rakefile --- Rakefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index d49ea27..6995c61 100644 --- a/Rakefile +++ b/Rakefile @@ -13,8 +13,7 @@ RPM_OPTS = '--define "_topdir %(pwd)/rpmbuild" --define "_builddir ' \ desc 'Generate regular and puppet-enterprise rbeapi RPMs for EOS' task rpm: :build do system "sed -e 's/^Version:.*/Version: #{Rbeapi::VERSION}/g' " \ - 'rbeapi-chef.spec.tmpl > rbeapi.spec' - # 'rbeapi.spec.tmpl > rbeapi.spec' + 'rbeapi.spec.tmpl > rbeapi.spec' system "rpmbuild #{RPM_OPTS} rbeapi.spec" RPMS = `find rpms/noarch -name "*rbeapi*rpm"` puts "\n################################################\n#" @@ -89,7 +88,7 @@ task all_rpms: :build do puts " rubygem-rbeapi-chef-#{Rbeapi::VERSION}-2.eos4.noarch.rpm \\" puts ' rubygem-inifile-chef-3.0.0-5.eos4.noarch.rpm \\' puts ' rubygem-netaddr-chef-1.5.1-4.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-0.2.1-5.eos4.noarch.rpm' + puts ' rubygem-net_http_unix-chef-0.2.1-5.eos4.noarch.rpm' puts ' Puppet Open Source: ' puts ' cd /mnt/flash; \\' puts " swix create rbeapi-#{Rbeapi::VERSION}-1.swix \\" From 4b3c9496dd99fea1815d2d281538c1cd6e0c9499 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Tue, 31 May 2016 14:58:55 -0400 Subject: [PATCH 32/60] Add -chef package for each RPM --- gems/inifile/inifile.spec.tmpl | 6 +++--- gems/net_http_unix/net_http_unix.spec.tmpl | 4 ++-- gems/netaddr/netaddr.spec.tmpl | 2 +- rbeapi.spec.tmpl | 5 +++++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/gems/inifile/inifile.spec.tmpl b/gems/inifile/inifile.spec.tmpl index 057c131..2b57fed 100644 --- a/gems/inifile/inifile.spec.tmpl +++ b/gems/inifile/inifile.spec.tmpl @@ -53,8 +53,8 @@ var2 = shoodle. Summary: Inifile rubygem packaged for Chef Group: Development/Languages Requires: chef -Provides: cehf-rubygem(%{gem_name}) = %{version} -Provides: cehf-rubygem-%{gem_name} = %{version} +Provides: chef-rubygem(%{gem_name}) = %{version} +Provides: chef-rubygem-%{gem_name} = %{version} %description chef The inifile rubygem packaged for Chef client on Arista EOS. @@ -109,7 +109,7 @@ GEM_OPTS="--no-document --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun chef -GEM=/opt/chef/enbedded/bin/gem +GEM=/opt/chef/embedded/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet3 diff --git a/gems/net_http_unix/net_http_unix.spec.tmpl b/gems/net_http_unix/net_http_unix.spec.tmpl index 39471e7..13858dd 100644 --- a/gems/net_http_unix/net_http_unix.spec.tmpl +++ b/gems/net_http_unix/net_http_unix.spec.tmpl @@ -23,8 +23,8 @@ Wrapper around Net::HTTP with AF_UNIX support. Group: Development/Languages Summary: Net_http_unix rubygem packaged for Chef client Requires: chef -Provides: chef(%{gem_name}) = %{version} -Provides: chef%{gem_name} = %{version} +Provides: chef-rubygem(%{gem_name}) = %{version} +Provides: chef-rubygem-%{gem_name} = %{version} %description chef %package puppet3 diff --git a/gems/netaddr/netaddr.spec.tmpl b/gems/netaddr/netaddr.spec.tmpl index 71c1d4c..52bc636 100644 --- a/gems/netaddr/netaddr.spec.tmpl +++ b/gems/netaddr/netaddr.spec.tmpl @@ -74,7 +74,7 @@ GEM_OPTS="--no-document --local" ${GEM} install ${GEM_OPTS} /%{gem_name}-%{version}.gem > /dev/null 2>&1 %preun chef -GEM=/opt/chef/ebmedded/bin/gem +GEM=/opt/chef/embedded/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %post puppet3 diff --git a/rbeapi.spec.tmpl b/rbeapi.spec.tmpl index 5d08b7d..8d1f9b4 100644 --- a/rbeapi.spec.tmpl +++ b/rbeapi.spec.tmpl @@ -35,6 +35,11 @@ Github iusses. Summary: Arista eAPI Ruby Library for Chef clients Group: Development/Languages Requires: chef +Requires: chef-rubygem(net_http_unix) +Requires: chef-rubygem(inifile) +Requires: chef-rubygem(netaddr) +Provides: chef-rubygem(%{gem_name}) = %{version} +Provides: chef-rubygem-%{gem_name} = %{version} %description chef The Ruby eAPI Client for Chef clients From 78a56602194b18de675668a9151c0ad72512e112 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Fri, 9 Sep 2016 11:54:21 -0400 Subject: [PATCH 33/60] Update net_http_unix version to 0.2.2 --- Rakefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Rakefile b/Rakefile index 6995c61..bb8de5f 100644 --- a/Rakefile +++ b/Rakefile @@ -88,14 +88,14 @@ task all_rpms: :build do puts " rubygem-rbeapi-chef-#{Rbeapi::VERSION}-2.eos4.noarch.rpm \\" puts ' rubygem-inifile-chef-3.0.0-5.eos4.noarch.rpm \\' puts ' rubygem-netaddr-chef-1.5.1-4.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-chef-0.2.1-5.eos4.noarch.rpm' + puts ' rubygem-net_http_unix-chef-0.2.2-5.eos4.noarch.rpm' puts ' Puppet Open Source: ' puts ' cd /mnt/flash; \\' puts " swix create rbeapi-#{Rbeapi::VERSION}-1.swix \\" puts " rubygem-rbeapi-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" puts ' rubygem-inifile-3.0.0-5.eos4.noarch.rpm \\' puts ' rubygem-netaddr-1.5.1-4.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-0.2.1-5.eos4.noarch.rpm' + puts ' rubygem-net_http_unix-0.2.2-5.eos4.noarch.rpm' puts ' Puppet-enterprise agent (3.x): ' puts ' cd/mnt/flash; \\' puts " swix create rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix \\" @@ -108,7 +108,7 @@ task all_rpms: :build do puts " rubygem-rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" puts ' rubygem-inifile-puppet-aio-3.0.0-5.eos4.noarch.rpm \\' puts ' rubygem-netaddr-puppet-aio-1.5.1-4.eos4.noarch.rpm \\' - puts ' rubygem-net_http_unix-puppet-aio-0.2.1-5.eos4.noarch.rpm' + puts ' rubygem-net_http_unix-puppet-aio-0.2.2-5.eos4.noarch.rpm' end desc 'Generate SWIX files from RPMs' @@ -121,7 +121,7 @@ task swix: :all_rpms do rubygem-rbeapi-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ rubygem-inifile-3.0.0-5.eos4.noarch.rpm \ rubygem-netaddr-1.5.1-4.eos4.noarch.rpm \ - rubygem-net_http_unix-0.2.1-5.eos4.noarch.rpm)" + rubygem-net_http_unix-0.2.2-5.eos4.noarch.rpm)" system "(cd rpms/noarch; rm -f rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix \ @@ -134,7 +134,7 @@ task swix: :all_rpms do rubygem-rbeapi-puppet-aio-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ rubygem-inifile-puppet-aio-3.0.0-5.eos4.noarch.rpm \ rubygem-netaddr-puppet-aio-1.5.1-4.eos4.noarch.rpm \ - rubygem-net_http_unix-puppet-aio-0.2.1-5.eos4.noarch.rpm)" + rubygem-net_http_unix-puppet-aio-0.2.2-5.eos4.noarch.rpm)" SWIXS = `find rpms/noarch -name "rbeapi*swix" -ls` puts "\n################################################\n#" puts "The following artifacts are in rpms/noarch/\n#{SWIXS}" From c965d96f0b5c3fd3ecf81abcfc99f5f1cbf65c55 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Fri, 9 Sep 2016 12:40:28 -0400 Subject: [PATCH 34/60] Bump rev numbers and add chef swix to Rakefile --- Rakefile | 10 ++++++++-- rbeapi.spec.tmpl | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Rakefile b/Rakefile index bb8de5f..fef65db 100644 --- a/Rakefile +++ b/Rakefile @@ -84,8 +84,8 @@ task all_rpms: :build do puts ' Examples: ' puts ' Chef client: ' puts ' cd /mnt/flash; \\' - puts " swix create rbeapi-chef-#{Rbeapi::VERSION}-2.swix \\" - puts " rubygem-rbeapi-chef-#{Rbeapi::VERSION}-2.eos4.noarch.rpm \\" + puts " swix create rbeapi-chef-#{Rbeapi::VERSION}-1.swix \\" + puts " rubygem-rbeapi-chef-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \\" puts ' rubygem-inifile-chef-3.0.0-5.eos4.noarch.rpm \\' puts ' rubygem-netaddr-chef-1.5.1-4.eos4.noarch.rpm \\' puts ' rubygem-net_http_unix-chef-0.2.2-5.eos4.noarch.rpm' @@ -122,6 +122,12 @@ task swix: :all_rpms do rubygem-inifile-3.0.0-5.eos4.noarch.rpm \ rubygem-netaddr-1.5.1-4.eos4.noarch.rpm \ rubygem-net_http_unix-0.2.2-5.eos4.noarch.rpm)" + system "(cd rpms/noarch; + rm -f rbeapi-chef-#{Rbeapi::VERSION}-1.swix; + #{SWIX} create rbeapi-chef-#{Rbeapi::VERSION}-1.swix \ + rubygem-rbeapi-chef-#{Rbeapi::VERSION}-1.eos4.noarch.rpm \ + rubygem-inifile-chef-3.0.0-5.eos4.noarch.rpm \ + rubygem-netaddr-chef-1.5.1-4.eos4.noarch.rpm)" system "(cd rpms/noarch; rm -f rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix; #{SWIX} create rbeapi-puppet3-#{Rbeapi::VERSION}-1.swix \ diff --git a/rbeapi.spec.tmpl b/rbeapi.spec.tmpl index 8d1f9b4..5bac2b4 100644 --- a/rbeapi.spec.tmpl +++ b/rbeapi.spec.tmpl @@ -3,7 +3,7 @@ Name: %{?enterprise:pe-}rubygem-%{gem_name} Version: REPLACEME -Release: 2.eos4 +Release: 1.eos4 Summary: Arista eAPI Ruby Library for the EOS command API Group: Development/Languages @@ -122,7 +122,7 @@ GEM=/opt/puppetlabs/puppet/bin/gem ${GEM} uninstall %{gem_name} --version '= %{version}' > /dev/null 2>&1 %changelog -* Tue May 24 2016 Jere Julian - 0.4.0-2 +* Tue May 24 2016 Jere Julian - 0.6.0-1 - Add Chef sub-package * Fri Oct 30 2015 Jere Julian - 0.4.0-1 From 252c61dc500c280778b0382e279f99c6288842ae Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Fri, 9 Sep 2016 12:49:23 -0400 Subject: [PATCH 35/60] Remove gen_commands and add_default for now --- lib/rbeapi/switchconfig.rb | 54 +------------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/lib/rbeapi/switchconfig.rb b/lib/rbeapi/switchconfig.rb index e4445e0..07dd49d 100644 --- a/lib/rbeapi/switchconfig.rb +++ b/lib/rbeapi/switchconfig.rb @@ -39,8 +39,6 @@ module SwitchConfig ## # Section class # - # XXX: Is this the right doc format for a class and accessors? - # # A switch configuration section consists of the command line that # enters into the configuration mode, an array of command strings # that are executed in the current configuration mode, a reference @@ -102,53 +100,6 @@ def get_child(line) nil end - ## - # Prepend the word 'default' to a cmd. - # - # @param cmd [String] A command string - # - # @return [String] Returns command string with word 'default' prepended. - def prepend_default(cmd) - # Return if the command is prepended by a default - return cmd unless cmd.scan(/^\s*default\s+/).empty? - # If the command is prepended by a no, then remove it. - new_cmd = cmd.sub(/^(\s*)(no\s+)/, '\1') - new_cmd.sub(/^(?\s*)/, '\kdefault ') - end - - ## - # Generates an array of commands for the current section. If the - # add_default option is set then each command is prepended with the - # word 'default'. Commands that enter a mode are not prepended with - # the word 'default'. Performs recursive calls to process children. - # - # @param opts [Hash] the options to create a message with. - # - # @option opts add_default [Boolean] Set to true to have commands - # prepended with the word 'default'. Default is false. - # - # @return [Array] Returns an array of commands that can be - # sent to a switch. - def gen_commands(opts = {}) - add_default = opts.fetch(:add_default, false) - - # Iterate over the commands, if the command has an associated - # child then process the child. This will preserve the order of - # the configuration. - ret_cmds = [] - cmds.each do |cmd| - child = get_child(cmd) - cmd = prepend_default(cmd) if add_default && !child - ret_cmds.push(cmd) - next unless child - child_cmds = child.gen_commands(opts) - next unless child_cmds.length > 0 - ret_cmds.push(child_cmds) - ret_cmds.flatten! - end - ret_cmds - end - ## # Private campare method to compare the commands between two Section # classes. @@ -255,16 +206,13 @@ class SwitchConfig # references to all sub-sections (children). # # { - # name: , # global:
, # } # # @param config [String] A string containing the switch configuration. # # @return [Section] Returns an instance of Section - # XXX Name is not really used - can delete - def initialize(name, config) - @name = name + def initialize(config) @indent = 3 chk_format(config) parse(config) From 4f57aa493609a0a428a1b4cfba0677abe74c67c9 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Fri, 9 Sep 2016 15:29:50 -0400 Subject: [PATCH 36/60] Update tests to match methos updates for this release --- spec/unit/rbeapi/switchconfig2_spec.rb | 8 +++--- spec/unit/rbeapi/switchconfig3_spec.rb | 36 +++---------------------- spec/unit/rbeapi/switchconfig_spec.rb | 37 +++++--------------------- 3 files changed, 14 insertions(+), 67 deletions(-) diff --git a/spec/unit/rbeapi/switchconfig2_spec.rb b/spec/unit/rbeapi/switchconfig2_spec.rb index 4d3eb0e..c5b5a9d 100644 --- a/spec/unit/rbeapi/switchconfig2_spec.rb +++ b/spec/unit/rbeapi/switchconfig2_spec.rb @@ -49,7 +49,7 @@ ' vrf cloud-mgmt'], [' no shutdown']] - subject { described_class.new('test', test_config) } + subject { described_class.new(test_config) } # SwitchConfig class methods describe '#initialize' do @@ -109,9 +109,9 @@ vrf cloud-mgmt shutdown EOS - swc_new = Rbeapi::SwitchConfig::SwitchConfig.new('', new_conf) - swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new('', org_new_diff) - swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new('', new_org_diff) + swc_new = Rbeapi::SwitchConfig::SwitchConfig.new(new_conf) + swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new(org_new_diff) + swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new(new_org_diff) expect(subject.compare(swc_new)[0]).to section_equal(swc_org_new.global) expect(subject.compare(swc_new)[1]).to section_equal(swc_new_org.global) end diff --git a/spec/unit/rbeapi/switchconfig3_spec.rb b/spec/unit/rbeapi/switchconfig3_spec.rb index f1b704a..34ebbfb 100644 --- a/spec/unit/rbeapi/switchconfig3_spec.rb +++ b/spec/unit/rbeapi/switchconfig3_spec.rb @@ -54,7 +54,7 @@ ' vrf cloud-mgmt'], [' no shutdown']] - subject { described_class.new('test', test_config) } + subject { described_class.new(test_config) } # SwitchConfig class methods describe '#initialize' do @@ -115,39 +115,11 @@ vrf cloud-mgmt shutdown EOS - swc_new = Rbeapi::SwitchConfig::SwitchConfig.new('', new_conf) - swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new('', org_new_diff) - swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new('', new_org_diff) + swc_new = Rbeapi::SwitchConfig::SwitchConfig.new(new_conf) + swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new(org_new_diff) + swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new(new_org_diff) expect(subject.compare(swc_new)[0]).to section_equal(swc_org_new.global) expect(subject.compare(swc_new)[1]).to section_equal(swc_new_org.global) end end - - # Section class methods - describe 'Section Class' do - describe '#gen_commands' do - conf = <<-EOS -no snmp-server enable traps bgp -management api http-commands - no shutdown - vrf cloud-mgmt - no shutdown -EOS - conf_array = conf.split("\n") - default_conf = <<-EOS -default snmp-server enable traps bgp -management api http-commands - default shutdown - vrf cloud-mgmt - default shutdown -EOS - default_array = default_conf.split("\n") - it 'Verify command correctly generated' do - swc = Rbeapi::SwitchConfig::SwitchConfig.new('', conf) - sc = swc.global - expect(sc.gen_commands).to eq(conf_array) - expect(sc.gen_commands(add_default: true)).to eq(default_array) - end - end - end end diff --git a/spec/unit/rbeapi/switchconfig_spec.rb b/spec/unit/rbeapi/switchconfig_spec.rb index 4116919..b7c4d3b 100644 --- a/spec/unit/rbeapi/switchconfig_spec.rb +++ b/spec/unit/rbeapi/switchconfig_spec.rb @@ -58,7 +58,7 @@ ! EOS - subject { described_class.new('test', test_config) } + subject { described_class.new(test_config) } # SwitchConfig class methods describe '#initialize' do @@ -80,7 +80,7 @@ it 'returns error for invalid indentation' do expect \ - { Rbeapi::SwitchConfig::SwitchConfig.new('bad_indent', bad_indent) }.to\ + { Rbeapi::SwitchConfig::SwitchConfig.new(bad_indent) }.to\ raise_error ArgumentError end end @@ -108,7 +108,7 @@ switchport mode trunk switchport trunk allowed vlan 100,200 EOS - sw_config = Rbeapi::SwitchConfig::SwitchConfig.new('', conf) + sw_config = Rbeapi::SwitchConfig::SwitchConfig.new(conf) expect(subject.compare(sw_config)[0].line).to eq('') expect(subject.compare(sw_config)[0].cmds).to eq([]) expect(subject.compare(sw_config)[0].children).to eq([]) @@ -134,9 +134,9 @@ interface Ethernet 2 switchport trunk allowed vlan 101,200 EOS - swc_new = Rbeapi::SwitchConfig::SwitchConfig.new('', new_conf) - swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new('', org_new_diff) - swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new('', new_org_diff) + swc_new = Rbeapi::SwitchConfig::SwitchConfig.new(new_conf) + swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new(org_new_diff) + swc_new_org = Rbeapi::SwitchConfig::SwitchConfig.new(new_org_diff) expect(subject.compare(swc_new)[0]).to section_equal(swc_org_new.global) expect(subject.compare(swc_new)[1]).to section_equal(swc_new_org.global) end @@ -183,30 +183,5 @@ expect(parent.get_child('child line')).to eq(child) end end - - describe '#gen_commands' do - conf = <<-EOS -vlan 101 -interface Ethernet 2 - switchport mode trunk - switchport trunk allowed vlan 101,200 -vlan 102 -EOS - conf_array = conf.split("\n") - default_conf = <<-EOS -default vlan 101 -interface Ethernet 2 - default switchport mode trunk - default switchport trunk allowed vlan 101,200 -default vlan 102 -EOS - default_array = default_conf.split("\n") - it 'Verify command correctly generated' do - swc = Rbeapi::SwitchConfig::SwitchConfig.new('', conf) - sc = swc.global - expect(sc.gen_commands).to eq(conf_array) - expect(sc.gen_commands(add_default: true)).to eq(default_array) - end - end end end From 72c53ae5697efe79466439a69afe03a605441f2f Mon Sep 17 00:00:00 2001 From: Florin Vinti Date: Wed, 14 Sep 2016 17:11:20 +0200 Subject: [PATCH 37/60] add spec tests for prefix lists - new unit and systems tests for prefix lists - prefixlists documentation update - fix prefix list key to 'prefix' --- lib/rbeapi/api/prefixlists.rb | 76 +++++-- spec/system/rbeapi/api/prefixlists_spec.rb | 198 +++++++++++++++++ .../rbeapi/api/prefixlists/default_spec.rb | 202 ++++++++++++++++++ .../api/prefixlists/fixture_prefixlists.text | 11 + 4 files changed, 464 insertions(+), 23 deletions(-) create mode 100644 spec/system/rbeapi/api/prefixlists_spec.rb create mode 100644 spec/unit/rbeapi/api/prefixlists/default_spec.rb create mode 100644 spec/unit/rbeapi/api/prefixlists/fixture_prefixlists.text diff --git a/lib/rbeapi/api/prefixlists.rb b/lib/rbeapi/api/prefixlists.rb index d0583aa..caa8924 100644 --- a/lib/rbeapi/api/prefixlists.rb +++ b/lib/rbeapi/api/prefixlists.rb @@ -43,22 +43,29 @@ module Api # class Prefixlists < Entity ## - # Returns the static routes configured on the node. + # Returns the prefix list configured on the node. # # @example - # { - # : { - # next_hop: , - # name: + # [ + # { + # seq: , + # action: , + # prefix: + # }, + # ..., + # { + # seq: , + # action: , + # prefix: # } - # } + # ] # # @param name [String] The name of the prefix-list to return. # - # @return [Hash The method will return all of the - # configured static routes on the node as a Ruby hash object. If - # there are no static routes configured, this method will return - # an empty hash. + # @return [Array] The method will return the configured + # prefix list on the node with all its sequences as a Ruby + # array of hashes, where each prefix is a hash object. + # If the prefix list is not found, a nil object is returned. def get(name) config = get_block("ip prefix-list #{name}") return nil unless config @@ -66,25 +73,48 @@ def get(name) entries = config.scan(/^\s{3}(?:seq\s)(\d+)\s(permit|deny)\s(.+)$/) entries.each_with_object([]) do |entry, arry| arry << { 'seq' => entry[0], 'action' => entry[1], - 'prefex' => entry[2] } + 'prefix' => entry[2] } end end ## - # Returns the static routes configured on the node. + # Returns all prefix lists configured on the node. # # @example # { - # : { - # next_hop: , - # name: - # } + # : [ + # { + # seq: , + # action: , + # prefix: + # }, + # ... + # { + # seq: , + # action: , + # prefix: + # } + # ], + # ..., + # : [ + # { + # seq: , + # action: , + # prefix: + # }, + # ... + # { + # seq: , + # action: , + # prefix: + # } + # ] # } # - # @return [Hash The method will return all of the - # configured static routes on the node as a Ruby hash object. If - # there are no static routes configured, this method will return - # an empty hash. + # @return [Hash] The method will return all the + # prefix lists configured on the node as a Ruby hash object. + # If there are no prefix lists configured, an empty hash will + # be returned. def getall lists = config.scan(/(?<=^ip\sprefix-list\s).+/) lists.each_with_object({}) do |name, hsh| @@ -100,7 +130,7 @@ def getall # # @return [Boolean] Returns true if the command completed successfully. def create(name) - configure "ip prefix-list #{name}" + configure("ip prefix-list #{name}") end ## @@ -120,7 +150,7 @@ def add_rule(name, action, prefix, seq = nil) cmd = "ip prefix-list #{name}" cmd << " seq #{seq}" if seq cmd << " #{action} #{prefix}" - configure cmd + configure(cmd) end ## @@ -134,7 +164,7 @@ def add_rule(name, action, prefix, seq = nil) def delete(name, seq = nil) cmd = "no ip prefix-list #{name}" cmd << " seq #{seq}" if seq - configure cmd + configure(cmd) end end end diff --git a/spec/system/rbeapi/api/prefixlists_spec.rb b/spec/system/rbeapi/api/prefixlists_spec.rb new file mode 100644 index 0000000..03f5cac --- /dev/null +++ b/spec/system/rbeapi/api/prefixlists_spec.rb @@ -0,0 +1,198 @@ +# +# Copyright (c) 2016, Arista Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Arista Networks nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +require 'spec_helper' + +require 'rbeapi/client' +require 'rbeapi/api/prefixlists' + +describe Rbeapi::Api::Prefixlists do + subject { described_class.new(node) } + + let(:node) do + Rbeapi::Client.config.read(fixture_file('dut.conf')) + Rbeapi::Client.connect_to('dut') + end + + describe '#get' do + before do + node.config(['no ip prefix-list test1', + 'ip prefix-list test1', + 'seq 10 permit 1.2.3.0/24', + 'seq 20 permit 2.3.4.0/24 le 30', + 'seq 30 deny 3.4.5.0/24 ge 26 le 30', + 'permit 5.6.7.16/28 eq 29']) + end + + let(:prefixlist) { subject.get('test1') } + + it 'returns the prefix list for an existing name' do + expect(prefixlist).to be_a_kind_of(Array) + end + + it 'returns all rules as hash' do + expect(prefixlist).to all ( be_an(Hash) ) + end + + it 'has all keys for each rule' do + prefixlist.each do |rule| + expect(rule).to have_key('seq') + expect(rule).to have_key('prefix') + expect(rule).to have_key('action') + end + end + + let(:values) do + [ + { + 'seq' => '10', + 'action' => 'permit', + 'prefix' => '1.2.3.0/24' + }, + { + 'seq' => '20', + 'action' => 'permit', + 'prefix' => '2.3.4.0/24 le 30' + }, + { + 'seq' => '30', + 'action' => 'deny', + 'prefix' => '3.4.5.0/24 ge 26 le 30' + }, + { + 'seq' => '40', + 'action' => 'permit', + 'prefix' => '5.6.7.16/28 eq 29' + } + ] + end + + it 'returns the correct values for all the keys' do + expect(prefixlist).to eq(values) + end + end + + describe '#getall' do + let(:del_pref_lists) { + subject.getall.keys.map { |k| "no ip prefix-list #{k}" } + } + + before do + node.config(del_pref_lists + + ['ip prefix-list test1', + 'seq 10 permit 1.2.3.0/24', + 'seq 20 permit 2.3.4.0/24 le 30', + 'seq 30 deny 3.4.5.0/24 ge 26 le 30', + 'permit 5.6.7.8/28', + 'ip prefix-list test2', + 'seq 10 permit 10.11.0.0/16', + 'seq 20 permit 10.12.0.0/16 le 24', + 'ip prefix-list test3']) + end + + let(:prefixlists) { subject.getall } + + it 'returns the collection as hash' do + expect(prefixlists).to be_a_kind_of(Hash) + end + + it 'returns all prefix lists as array' do + expect(prefixlists).to all ( be_an(Array) ) + end + + it 'has three prefix lists' do + expect(prefixlists.size).to eq(3) + end + end + + describe '#create' do + before do + node.config('no ip prefix-list test4') + end + + it 'creates a new prefix list' do + expect(subject.get('test4')).to eq(nil) + expect(subject.create('test4')).to be_truthy + expect(subject.get('test4')).to eq([]) + expect(subject.get('test4').size).to eq(0) + end + end + + describe '#add_rule' do + before do + node.config(['no ip prefix-list test5', + 'ip prefix-list test5']) + end + + it 'adds rule to an existing prefix list' do + expect(subject.get('test5')).to eq([]) + expect(subject.add_rule('test5', 'permit', '1.1.1.0/24')).to be_truthy + expect(subject.get('test5')).to eq([{ + "seq" => "10", + "action" => "permit", + "prefix" => "1.1.1.0/24"}]) + end + + it 'adds rule to a non-existent prefix list' do + expect(subject.get('test6')).to eq(nil) + expect(subject.add_rule('test6', 'deny', '2.2.2.0/24')).to be_truthy + expect(subject.get('test6')).to eq([{ + "seq" => "10", + "action" => "deny", + "prefix" => "2.2.2.0/24"}]) + end + end + + describe '#delete' do + before do + node.config(['no ip prefix-list test7', + 'no ip prefix-list test8', + 'ip prefix-list test7', + 'seq 10 permit 7.7.0.0/16', + 'ip prefix-list test8', + 'seq 10 permit 8.8.0.0/16', + 'deny 9.9.0.0/16 le 24']) + end + + it 'delets a prefix list' do + expect(subject.get('test7')).to be_truthy + expect(subject.delete('test7')).to be_truthy + expect(subject.get('test7')).to eq(nil) + end + + it 'deletes a rule in the prefix list' do + expect(subject.get('test8')).to be_truthy + expect(subject.delete('test8', 20)).to be_truthy + expect(subject.get('test8').size).to eq(1) + expect(subject.get('test8')[1]).to eq(nil) + end + end +end \ No newline at end of file diff --git a/spec/unit/rbeapi/api/prefixlists/default_spec.rb b/spec/unit/rbeapi/api/prefixlists/default_spec.rb new file mode 100644 index 0000000..160eba5 --- /dev/null +++ b/spec/unit/rbeapi/api/prefixlists/default_spec.rb @@ -0,0 +1,202 @@ +# +# Copyright (c) 2016, Arista Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Arista Networks nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +require 'spec_helper' + +require 'rbeapi/api/prefixlists' + +include FixtureHelpers + +describe Rbeapi::Api::Prefixlists do + subject { described_class.new(node) } + + let(:node) { double('node') } + + def prefixlists + prefixlists = Fixtures[:prefixlists] + return prefixlists if prefixlists + fixture('prefixlists', format: :text, dir: File.dirname(__FILE__)) + end + + before :each do + allow(subject.node).to receive(:running_config).and_return(prefixlists) + end + + describe '#get' do + let(:resource) { subject.get('test1') } + + let(:prefixlist) do + [{ + 'seq' => '10', + 'action' => 'permit', + 'prefix' => '1.2.3.0/24' + }, + { + 'seq' => '20', + 'action' => 'permit', + 'prefix' => '2.3.4.0/24 le 30' + }, + { + 'seq' => '30', + 'action' => 'permit', + 'prefix' => '3.4.5.0/24 ge 26 le 30' + }] + end + + let(:keys) { ['seq', 'action', 'prefix'] } + + it 'returns the prefix list for an existing name' do + expect(resource).to eq(prefixlist) + end + + it 'returns an array of prefixes' do + expect(resource).to be_a_kind_of(Array) + end + + it 'has three prefixes' do + expect(resource.size).to eq(3) + end + + it 'has all keys' do + resource.each do |prefix| + expect(prefix.keys).to match_array(keys) + end + end + + let(:nonexistent) { subject.get('nonexistent') } + it 'returns nil for a non-existing name' do + expect(nonexistent).to eq(nil) + end + end + + describe '#getall' do + let(:resource) { subject.getall } + + let(:plists) do + { + "test1" => [ + { + "seq" => "10", + "action" => "permit", + "prefix" => "1.2.3.0/24" + }, + { + "seq" => "20", + "action" => "permit", + "prefix" => "2.3.4.0/24 le 30" + }, + { + "seq" => "30", + "action" => "permit", + "prefix" => "3.4.5.0/24 ge 26 le 30" + } + ], + "test2" => [ + { + "seq" => "10", + "action" => "permit", + "prefix" => "10.11.0.0/16" + }, + { + "seq" => "20", + "action" => "permit", + "prefix" => "10.12.0.0/16 le 24" + } + ], + "test3" => [] + } + end + + it 'returns all prefix lists' do + expect(resource).to eq(plists) + end + + it 'returns a hash' do + expect(resource).to be_a_kind_of(Hash) + end + + it 'has three prefix lists' do + expect(resource.size).to eq(3) + end + end + + describe '#create' do + it 'creates a new prefix list' do + expect(node).to receive(:config).with('ip prefix-list plist1') + expect(subject.create('plist1')).to be_truthy + end + + it 'creates an existing prefix list' do + expect(node).to receive(:config).with('ip prefix-list test1') + expect(subject.create('test1')).to be_truthy + end + end + + describe '#add_rule' do + it 'adds rule to existing prefix list' do + expect(node).to receive(:config).with('ip prefix-list test1 seq 25 permit 9.8.7.0/24') + expect(subject.add_rule('test1', 'permit','9.8.7.0/24', '25')).to be_truthy + end + + it 'adds rule to existing prefix list w/o seq' do + expect(node).to receive(:config).with('ip prefix-list test1 permit 8.7.6.0/24') + expect(subject.add_rule('test1', 'permit', '8.7.6.0/24')).to be_truthy + end + + it 'adds rule to non-existing prefix list' do + expect(node).to receive(:config).with('ip prefix-list plist2 seq 10 permit 6.5.4.128/25') + expect(subject.add_rule('plist2', 'permit', '6.5.4.128/25', '10')).to be_truthy + end + + it 'adds rule to non-existing prefix list w/o seq' do + expect(node).to receive(:config).with('ip prefix-list plist2 deny 5.4.3.0/25') + expect(subject.add_rule('plist2', 'deny', '5.4.3.0/25')).to be_truthy + end + + it 'overwrites existing rule' do + expect(node).to receive(:config).with('ip prefix-list test1 seq 20 permit 2.3.5.0/24 le 28') + expect(subject.add_rule('test1', 'permit', '2.3.5.0/24 le 28', '20')).to be_truthy + end + end + + describe '#delete' do + it 'deletes a prefix-list' do + expect(node).to receive(:config).with('no ip prefix-list test1') + expect(subject.delete('test1')) + end + + it 'deletes a rule from a prefix-list' do + expect(node).to receive(:config).with('no ip prefix-list test2 seq 10') + expect(subject.delete('test2', '10')) + end + end + +end \ No newline at end of file diff --git a/spec/unit/rbeapi/api/prefixlists/fixture_prefixlists.text b/spec/unit/rbeapi/api/prefixlists/fixture_prefixlists.text new file mode 100644 index 0000000..a02a489 --- /dev/null +++ b/spec/unit/rbeapi/api/prefixlists/fixture_prefixlists.text @@ -0,0 +1,11 @@ +ip prefix-list test1 + seq 10 permit 1.2.3.0/24 + seq 20 permit 2.3.4.0/24 le 30 + seq 30 permit 3.4.5.0/24 ge 26 le 30 +! +ip prefix-list test2 + seq 10 permit 10.11.0.0/16 + seq 20 permit 10.12.0.0/16 le 24 +! +ip prefix-list test3 +! \ No newline at end of file From 6188d7f98fcbb5b0851fd8c04d34eb1fb2788de6 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 15 Sep 2016 12:25:16 -0400 Subject: [PATCH 38/60] Ensure get_config, running_config, and startup_config return sane output - Fixes #127. Returns nil when the requested config does not exist. - An empty config will return an empty string (''). - Any other command error will raise CommandError. --- lib/rbeapi/client.rb | 11 ++++++++++- spec/unit/rbeapi/client_spec.rb | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/client.rb b/lib/rbeapi/client.rb index e5d04d8..27cd3d4 100644 --- a/lib/rbeapi/client.rb +++ b/lib/rbeapi/client.rb @@ -511,7 +511,16 @@ def get_config(opts = {}) config = opts.fetch(:config, 'running-config') params = opts.fetch(:params, '') as_string = opts.fetch(:as_string, false) - result = run_commands("show #{config} #{params}", encoding: 'text') + begin + result = run_commands("show #{config} #{params}", encoding: 'text') + rescue Rbeapi::Eapilib::CommandError => error + if ( error.to_s =~ /show (running|startup)-config/ ) + #result = [{"output"=>""}] + return nil + else + raise error + end + end return result.first['output'].strip.split("\n") unless as_string result.first['output'].strip end diff --git a/spec/unit/rbeapi/client_spec.rb b/spec/unit/rbeapi/client_spec.rb index 7e4fbd9..d583bb6 100644 --- a/spec/unit/rbeapi/client_spec.rb +++ b/spec/unit/rbeapi/client_spec.rb @@ -209,4 +209,38 @@ def wildcard_conf host: 'test2') end end + + describe '#get_config' do + def startup_config + "! Command: show running-config\n! device: jere-debug-agent1 (vEOS, EOS-4.14.9.1M)\n!\n! boot system flash:/vEOS-4.14.9.1M.swi\n!\nip routing vrf MGMT\n!\nmanagement api http-commands\n no protocol https\n protocol unix-socket\n no shutdown\n vrf MGMT\n no shutdown\n!\nmanagement ssh\n vrf MGMT\n no shutdown\n!\n!\nend\n" + end + + def startup_config_response + [{"output"=>startup_config}] + end + + let(:node) do + subject.config.read(fixture_file('dut.conf')) + subject.connect_to('dut') + end + + before(:each) do + allow(node).to receive(:run_commands) { startup_config_response } + end + + it 'with no arguments returns the startup-config' do + expect(node.get_config()).to eq(startup_config.strip.split("\n")) + end + + it 'with no arguments and an empty startup-config returns the startup-config' do + allow(node).to receive(:run_commands) { [{"output"=>""}] } + expect(node.get_config()).to eq([]) + end + + it 'with no arguments and no startup-config returns nil' do + msg = "CLI command 2 of 2 'show startup-config' failed: could not run command" + allow(node).to receive(:run_commands).and_raise(Rbeapi::Eapilib::CommandError.new(msg, 1000)) + expect(node.get_config()).to be_nil + end + end end From 883d8c90beb1a23d562f4b8e5da6b98c291cb320 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 15 Sep 2016 16:07:52 -0400 Subject: [PATCH 39/60] Treat banner sections as a single string. Fixes #135 - Banners are multiline strings and should be excluded from indention checks and otherwise treated as a single object. --- lib/rbeapi/switchconfig.rb | 30 +++++++++++++++ spec/unit/rbeapi/switchconfig_spec.rb | 54 ++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/switchconfig.rb b/lib/rbeapi/switchconfig.rb index 07dd49d..8edabf7 100644 --- a/lib/rbeapi/switchconfig.rb +++ b/lib/rbeapi/switchconfig.rb @@ -228,7 +228,17 @@ def initialize(config) # @return [boolean] Returns true if format is good, otherwise raises # an argument error. def chk_format(config) + skip = false + multiline_cmds = ['^banner'] config.each_line do |line| + skip = true if multiline_cmds.any? { |cmd| line =~ /#{cmd}/ } + if skip + if line =~ /^EOF$/ + skip = false + else + next + end + end ind = line[/\A */].size if ind % @indent != 0 fail ArgumentError, 'SwitchConfig indentation must be multiple of '\ @@ -248,6 +258,7 @@ def chk_format(config) # Lines starting with '!' (comments) are ignored # # @param config [String] A string containing the switch configuration. + # rubocop:disable Metrics/MethodLength def parse(config) # Setup global section section = Section.new('', nil) @@ -255,7 +266,25 @@ def parse(config) prev_indent = 0 prev_line = '' + combine = false + longline = [] + multiline_cmds = ['^banner'] + config.each_line do |line| + if multiline_cmds.any? { |cmd| line =~ /#{cmd}/ } + longline = [] + combine = true + end + if combine + longline << line + if line =~ /^EOF$/ + line = longline.join + combine = false + else + next + end + end + # Ignore comment lines and the end statement if there # XXX Fix parsing end next if line.start_with?('!') || line.start_with?('end') @@ -280,6 +309,7 @@ def parse(config) end end private :parse + # rubocop:enable Metrics/MethodLength ## # Campare the current SwitchConfig class with another SwitchConfig class. diff --git a/spec/unit/rbeapi/switchconfig_spec.rb b/spec/unit/rbeapi/switchconfig_spec.rb index b7c4d3b..3038620 100644 --- a/spec/unit/rbeapi/switchconfig_spec.rb +++ b/spec/unit/rbeapi/switchconfig_spec.rb @@ -37,6 +37,7 @@ include Rbeapi::SwitchConfig describe Rbeapi::SwitchConfig::SwitchConfig do + # rubocop:disable Style/TrailingWhitespace test_config = <<-EOS ! Config Description Comment vlan 100 @@ -45,8 +46,20 @@ switchport mode trunk switchport trunk allowed vlan 100,200 ! +banner motd +This is my + multiline + banner +ends here + +EOF +! EOS - test_config_global = ['vlan 100', 'interface Ethernet 2'] + # rubocop:enable Style/TrailingWhitespace + test_config_global = [ + 'vlan 100', + 'interface Ethernet 2', + "banner motd\nThis is my \n multiline\n banner\nends here\n\nEOF"] cmds = [' switchport mode trunk', ' switchport trunk allowed vlan 100,200'] @@ -57,6 +70,20 @@ switchport access vlan 100 ! EOS + # rubocop:disable Style/TrailingWhitespace + awkward_indent = <<-EOS +! +banner motd +This is my + multiline + banner +that ends here + +EOF +! +end +EOS + # rubocop:enable Style/TrailingWhitespace subject { described_class.new(test_config) } @@ -83,6 +110,12 @@ { Rbeapi::SwitchConfig::SwitchConfig.new(bad_indent) }.to\ raise_error ArgumentError end + + it 'does not return an error for tricky indentation' do + expect \ + { Rbeapi::SwitchConfig::SwitchConfig.new(awkward_indent) }.not_to\ + raise_error + end end describe '#compare' do @@ -102,12 +135,21 @@ end it 'Verify compare of same switch configs without comment' do + # rubocop:disable Style/TrailingWhitespace conf = <<-EOS vlan 100 interface Ethernet 2 switchport mode trunk switchport trunk allowed vlan 100,200 +banner motd +This is my + multiline + banner +ends here + +EOF EOS + # rubocop:enable Style/TrailingWhitespace sw_config = Rbeapi::SwitchConfig::SwitchConfig.new(conf) expect(subject.compare(sw_config)[0].line).to eq('') expect(subject.compare(sw_config)[0].cmds).to eq([]) @@ -118,12 +160,22 @@ end it 'Verify compare of different vlan id' do + # rubocop:disable Style/TrailingWhitespace new_conf = <<-EOS vlan 101 interface Ethernet 2 switchport mode trunk switchport trunk allowed vlan 101,200 +! +banner motd +This is my + multiline + banner +ends here + +EOF EOS + # rubocop:enable Style/TrailingWhitespace org_new_diff = <<-EOS vlan 100 interface Ethernet 2 From 2116ce3c9d3e521ef437e939878008c4f655f613 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 15 Sep 2016 16:36:11 -0400 Subject: [PATCH 40/60] Fix rubocop warnings --- lib/rbeapi/api/dns.rb | 2 ++ lib/rbeapi/api/interfaces.rb | 7 ++++--- lib/rbeapi/api/ipinterfaces.rb | 2 +- lib/rbeapi/api/stp.rb | 2 +- lib/rbeapi/api/varp.rb | 2 ++ lib/rbeapi/api/vrrp.rb | 4 ++++ spec/system/rbeapi/api/interfaces_base_spec.rb | 9 ++++++--- .../rbeapi/api/interfaces_portchannel_spec.rb | 18 ++++++++++++------ .../system/rbeapi/api/interfaces_vxlan_spec.rb | 3 ++- spec/system/rbeapi/api/ipinterfaces_spec.rb | 6 ++++-- spec/system/rbeapi/api/stp_instances_spec.rb | 10 +++++----- spec/system/rbeapi/api/switchports_spec.rb | 12 ++++++++---- .../rbeapi/api/interfaces/portchannel_spec.rb | 9 +++++---- .../rbeapi/api/switchports/default_spec.rb | 3 ++- 14 files changed, 58 insertions(+), 31 deletions(-) diff --git a/lib/rbeapi/api/dns.rb b/lib/rbeapi/api/dns.rb index 137faee..adfe9a5 100644 --- a/lib/rbeapi/api/dns.rb +++ b/lib/rbeapi/api/dns.rb @@ -206,6 +206,7 @@ def remove_name_server(server) # default keyword argument. # # @return [Boolean] Returns true if the commands completed successfully. + # rubocop:disable Metrics/MethodLength def set_domain_list(opts = {}) value = opts[:value] enable = opts.fetch(:enable, true) @@ -233,6 +234,7 @@ def set_domain_list(opts = {}) end configure cmds end + # rubocop:enable Metrics/MethodLength ## # add_domain_list adds an ip domain-list. diff --git a/lib/rbeapi/api/interfaces.rb b/lib/rbeapi/api/interfaces.rb index 917cd09..31af818 100644 --- a/lib/rbeapi/api/interfaces.rb +++ b/lib/rbeapi/api/interfaces.rb @@ -365,7 +365,7 @@ def set_shutdown(name, opts = {}) # # @return [Boolean] Returns true if the command completed successfully. def set_load_interval(name, opts = {}) - commands = command_builder("load-interval", opts) + commands = command_builder('load-interval', opts) configure_interface(name, commands) end end @@ -377,7 +377,7 @@ class EthernetInterface < BaseInterface DEFAULT_ETH_FLOWC_TX = 'off' DEFAULT_ETH_FLOWC_RX = 'off' DEFAULT_SPEED = 'default' - DEFAULT_LACP_PRIORITY = 32768 + DEFAULT_LACP_PRIORITY = 32_768 ## # get returns the specified Ethernet interface resource hash that @@ -925,7 +925,8 @@ def set_minimum_links(name, opts = {}) # # @return [Boolean] Returns true if the command completed successfully. def set_members(name, members, mode = nil) - fail ArgumentError, 'members must be an Array' unless members.is_a?(Array) + fail ArgumentError, 'members must be an Array' unless + members.is_a?(Array) current_members = Set.new parse_members(name)[:members] members = Set.new members diff --git a/lib/rbeapi/api/ipinterfaces.rb b/lib/rbeapi/api/ipinterfaces.rb index 8451778..163b421 100644 --- a/lib/rbeapi/api/ipinterfaces.rb +++ b/lib/rbeapi/api/ipinterfaces.rb @@ -366,7 +366,7 @@ def set_helper_addresses(name, opts = {}) # # @return [Boolean] Returns true if the command completed successfully. def set_load_interval(name, opts = {}) - cmds = command_builder("load-interval", opts) + cmds = command_builder('load-interval', opts) configure_interface(name, cmds) end end diff --git a/lib/rbeapi/api/stp.rb b/lib/rbeapi/api/stp.rb index d0cde00..edd6189 100644 --- a/lib/rbeapi/api/stp.rb +++ b/lib/rbeapi/api/stp.rb @@ -206,7 +206,7 @@ def getall def parse_instances config = get_block('spanning-tree mst configuration') response = config.scan(/(?<=^\s{3}instance\s)\d+/) - response.push("0", "1").uniq! + response.push('0', '1').uniq! response end private :parse_instances diff --git a/lib/rbeapi/api/varp.rb b/lib/rbeapi/api/varp.rb index 64fdc53..9d52480 100644 --- a/lib/rbeapi/api/varp.rb +++ b/lib/rbeapi/api/varp.rb @@ -199,6 +199,7 @@ def parse_addresses(config) # @option opts default [Boolean] The value should be set to default. # # @return [Boolean] True if the commands succeeds otherwise False. + # rubocop:disable Metrics/MethodLength def set_addresses(name, opts = {}) value = opts[:value] enable = opts.fetch(:enable, true) @@ -224,6 +225,7 @@ def set_addresses(name, opts = {}) end configure(cmds) end + # rubocop:enable Metrics/MethodLength ## # The add_address method assigns one virtual IPv4 address. diff --git a/lib/rbeapi/api/vrrp.rb b/lib/rbeapi/api/vrrp.rb index 677a4e2..463ed6e 100644 --- a/lib/rbeapi/api/vrrp.rb +++ b/lib/rbeapi/api/vrrp.rb @@ -510,6 +510,8 @@ def parse_delay_reload(config, vrid) # of the tracked interface, and the amount to decrement the priority. # # @return [Boolean] Returns true if the command completed successfully. + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, + # rubocop:disable Metrics/PerceivedComplexity def create(name, vrid, opts = {}) fail ArgumentError, 'create has no options set' if opts.empty? @@ -570,6 +572,8 @@ def create(name, vrid, opts = {}) cmds += build_tracks_cmd(name, vrid, opts[:track]) if opts.key?(:track) configure_interface(name, cmds) end + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, + # rubocop:enable Metrics/PerceivedComplexity ## # delete will delete the virtual router ID on the interface from the diff --git a/spec/system/rbeapi/api/interfaces_base_spec.rb b/spec/system/rbeapi/api/interfaces_base_spec.rb index 2e40911..4c26cd5 100644 --- a/spec/system/rbeapi/api/interfaces_base_spec.rb +++ b/spec/system/rbeapi/api/interfaces_base_spec.rb @@ -20,7 +20,8 @@ describe '#get' do context 'with interface Loopback' do let(:entity) do - { name: 'Loopback0', type: 'generic', description: '', shutdown: false, load_interval: '' } + { name: 'Loopback0', type: 'generic', description: '', shutdown: false, + load_interval: '' } end before { node.config(['no interface Loopback0', 'interface Loopback0']) } @@ -33,7 +34,8 @@ context 'with interface Port-Channel' do let(:entity) do { name: 'Port-Channel1', type: 'portchannel', description: '', - shutdown: false, load_interval: '', members: [], lacp_mode: 'on', minimum_links: '0', + shutdown: false, load_interval: '', members: [], lacp_mode: 'on', + minimum_links: '0', lacp_fallback: 'disabled', lacp_timeout: '90' } end @@ -50,7 +52,8 @@ context 'with interface Vxlan' do let(:entity) do { name: 'Vxlan1', type: 'vxlan', description: '', - shutdown: false, load_interval: '', source_interface: '', multicast_group: '', + shutdown: false, load_interval: '', source_interface: '', + multicast_group: '', udp_port: 4789, flood_list: [], vlans: {} } end diff --git a/spec/system/rbeapi/api/interfaces_portchannel_spec.rb b/spec/system/rbeapi/api/interfaces_portchannel_spec.rb index 9ac2a29..c0e6f64 100644 --- a/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +++ b/spec/system/rbeapi/api/interfaces_portchannel_spec.rb @@ -14,7 +14,8 @@ describe '#get' do let(:entity) do { name: 'Port-Channel1', type: 'portchannel', description: '', - shutdown: false, load_interval: '', members: [], lacp_mode: 'on', minimum_links: '0', + shutdown: false, load_interval: '', members: [], lacp_mode: 'on', + minimum_links: '0', lacp_timeout: '90', lacp_fallback: 'disabled' } end @@ -278,21 +279,26 @@ it 'sets the load-interval value on the interface' do expect(subject.get('Port-Channel1')[:load_interval]).to eq('') - expect(subject.set_load_interval('Port-Channel1', value: '10')).to be_truthy + expect(subject.set_load_interval('Port-Channel1', + value: '10')).to be_truthy expect(subject.get('Port-Channel1')[:load_interval]).to eq('10') end it 'negates the load-interval' do - expect(subject.set_load_interval('Port-Channel1', value: '20')).to be_truthy + expect(subject.set_load_interval('Port-Channel1', + value: '20')).to be_truthy expect(subject.get('Port-Channel1')[:load_interval]).to eq('20') - expect(subject.set_load_interval('Port-Channel1', enable: false)).to be_truthy + expect(subject.set_load_interval('Port-Channel1', + enable: false)).to be_truthy expect(subject.get('Port-Channel1')[:load_interval]).to eq('') end it 'defaults the load-interval' do - expect(subject.set_load_interval('Port-Channel1', value: '10')).to be_truthy + expect(subject.set_load_interval('Port-Channel1', + value: '10')).to be_truthy expect(subject.get('Port-Channel1')[:load_interval]).to eq('10') - expect(subject.set_load_interval('Port-Channel1', default: true)).to be_truthy + expect(subject.set_load_interval('Port-Channel1', + default: true)).to be_truthy expect(subject.get('Port-Channel1')[:load_interval]).to eq('') end end diff --git a/spec/system/rbeapi/api/interfaces_vxlan_spec.rb b/spec/system/rbeapi/api/interfaces_vxlan_spec.rb index cfb45e1..149334a 100644 --- a/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +++ b/spec/system/rbeapi/api/interfaces_vxlan_spec.rb @@ -13,7 +13,8 @@ describe '#get' do let(:entity) do - { name: 'Vxlan1', type: 'vxlan', description: '', shutdown: false, load_interval: '', + { name: 'Vxlan1', type: 'vxlan', description: '', shutdown: false, + load_interval: '', source_interface: '', multicast_group: '', udp_port: 4789, flood_list: [], vlans: {} } end diff --git a/spec/system/rbeapi/api/ipinterfaces_spec.rb b/spec/system/rbeapi/api/ipinterfaces_spec.rb index dee6a68..d09a9ab 100644 --- a/spec/system/rbeapi/api/ipinterfaces_spec.rb +++ b/spec/system/rbeapi/api/ipinterfaces_spec.rb @@ -13,7 +13,8 @@ describe '#get' do let(:entity) do - { address: '77.99.99.99/24', mtu: '1500', helper_addresses: [], load_interval: '' } + { address: '77.99.99.99/24', mtu: '1500', helper_addresses: [], + load_interval: '' } end before do @@ -159,7 +160,8 @@ describe '#set_load_interval' do before do - node.config(['default interface Ethernet1', 'interface Ethernet1', 'no switchport']) + node.config(['default interface Ethernet1', 'interface Ethernet1', + 'no switchport']) end it 'sets the load-interval value on the interface' do diff --git a/spec/system/rbeapi/api/stp_instances_spec.rb b/spec/system/rbeapi/api/stp_instances_spec.rb index dffb71f..d36dc74 100644 --- a/spec/system/rbeapi/api/stp_instances_spec.rb +++ b/spec/system/rbeapi/api/stp_instances_spec.rb @@ -92,7 +92,7 @@ it 'set the instance priority to default' do expect(subject.set_priority('10', value: '16384', - default: true)).to be_truthy + default: true)).to be_truthy expect(subject.get('10')[:priority]).to eq('32768') end @@ -104,8 +104,8 @@ it 'set the instance priority to enable false' do expect(subject.set_priority('10', value: '16384', - default: false, - enable: false)).to be_truthy + default: false, + enable: false)).to be_truthy expect(subject.get('10')[:priority]).to eq('32768') end @@ -118,8 +118,8 @@ it 'set the instance priority to enable true' do expect(subject.set_priority('10', value: '16384', - default: false, - enable: true)).to be_truthy + default: false, + enable: true)).to be_truthy expect(subject.get('10')[:priority]).to eq('16384') end diff --git a/spec/system/rbeapi/api/switchports_spec.rb b/spec/system/rbeapi/api/switchports_spec.rb index b540ec6..9177b14 100644 --- a/spec/system/rbeapi/api/switchports_spec.rb +++ b/spec/system/rbeapi/api/switchports_spec.rb @@ -194,15 +194,18 @@ it 'sets vlan 8-10 and 100 to the trunk allowed vlans' do node.config(['interface Ethernet1', 'switchport trunk allowed vlan none']) expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', '100'])) + expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', + '100'])) .to be_truthy - expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['8-10', '100']) + expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['8-10', + '100']) end it 'negate switchport trunk allowed vlan' do node.config(['interface Ethernet1', 'switchport trunk allowed vlan none']) expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', '100'])) + expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', + '100'])) .to be_truthy expect(subject.get('Ethernet1')[:trunk_allowed_vlans]) .to eq(['8-10', '100']) @@ -214,7 +217,8 @@ it 'default switchport trunk allowed vlan' do node.config(['interface Ethernet1', 'switchport trunk allowed vlan none']) expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', '100'])) + expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10', + '100'])) .to be_truthy expect(subject.get('Ethernet1')[:trunk_allowed_vlans]) .to eq(['8-10', '100']) diff --git a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb index 4a44988..3d1800c 100644 --- a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb @@ -31,8 +31,8 @@ def interfaces let(:resource) { subject.get('Port-Channel1') } let(:keys) do - [:type, :shutdown, :load_interval, :description, :name, :members, :lacp_mode, - :minimum_links, :lacp_timeout, :lacp_fallback] + [:type, :shutdown, :load_interval, :description, :name, :members, + :lacp_mode, :minimum_links, :lacp_timeout, :lacp_fallback] end it 'returns an ethernet resource as a hash' do @@ -144,8 +144,9 @@ def interfaces describe '#set_members' do it 'raises an ArgumentError if members is not an array' do - expect { subject.set_members('Port-Channel1', - 'Ethernet3') } + expect + subject.set_members('Port-Channel1', + 'Ethernet3') .to raise_error(ArgumentError) end end diff --git a/spec/unit/rbeapi/api/switchports/default_spec.rb b/spec/unit/rbeapi/api/switchports/default_spec.rb index 5efded3..5c72d7c 100644 --- a/spec/unit/rbeapi/api/switchports/default_spec.rb +++ b/spec/unit/rbeapi/api/switchports/default_spec.rb @@ -198,7 +198,8 @@ def switchports it 'sets vlan 8-10 and 100 to the trunk allowed vlans' do expect(node).to receive(:config) .with(['interface Ethernet1', 'switchport trunk allowed vlan 8-10,100']) - expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10','100'])) + expect(subject.set_trunk_allowed_vlans('Ethernet1', + value: ['8-10', '100'])) .to be_truthy end From accfa5a1ac2248461994792d6b606c4aa7d691f3 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Mon, 19 Sep 2016 14:33:49 -0400 Subject: [PATCH 41/60] Fix long line --- spec/unit/rbeapi/api/interfaces/portchannel_spec.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb index 3d1800c..9fb9833 100644 --- a/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +++ b/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb @@ -144,10 +144,8 @@ def interfaces describe '#set_members' do it 'raises an ArgumentError if members is not an array' do - expect - subject.set_members('Port-Channel1', - 'Ethernet3') - .to raise_error(ArgumentError) + expect { subject.set_members('Port-Channel1', 'Ethernet3') }.to \ + raise_error(ArgumentError) end end end From 4720272605813322efb0f1f3333057a139a2d9f0 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Mon, 19 Sep 2016 16:51:38 -0400 Subject: [PATCH 42/60] Remove dead code --- lib/rbeapi/client.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/rbeapi/client.rb b/lib/rbeapi/client.rb index 27cd3d4..491dd14 100644 --- a/lib/rbeapi/client.rb +++ b/lib/rbeapi/client.rb @@ -515,7 +515,6 @@ def get_config(opts = {}) result = run_commands("show #{config} #{params}", encoding: 'text') rescue Rbeapi::Eapilib::CommandError => error if ( error.to_s =~ /show (running|startup)-config/ ) - #result = [{"output"=>""}] return nil else raise error From 38cbf0dd2be6ddfef923709ed5c7331a43c54d67 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Tue, 20 Sep 2016 11:22:04 -0400 Subject: [PATCH 43/60] Move multiline_cmds to a class variable and include EOS 'comment' blocks in tests --- lib/rbeapi/switchconfig.rb | 7 +++--- spec/unit/rbeapi/switchconfig_spec.rb | 35 +++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/lib/rbeapi/switchconfig.rb b/lib/rbeapi/switchconfig.rb index 8edabf7..8ff0ce9 100644 --- a/lib/rbeapi/switchconfig.rb +++ b/lib/rbeapi/switchconfig.rb @@ -214,6 +214,7 @@ class SwitchConfig # @return [Section] Returns an instance of Section def initialize(config) @indent = 3 + @multiline_cmds = ['^banner'] chk_format(config) parse(config) end @@ -229,9 +230,8 @@ def initialize(config) # an argument error. def chk_format(config) skip = false - multiline_cmds = ['^banner'] config.each_line do |line| - skip = true if multiline_cmds.any? { |cmd| line =~ /#{cmd}/ } + skip = true if @multiline_cmds.any? { |cmd| line =~ /#{cmd}/ } if skip if line =~ /^EOF$/ skip = false @@ -268,10 +268,9 @@ def parse(config) prev_line = '' combine = false longline = [] - multiline_cmds = ['^banner'] config.each_line do |line| - if multiline_cmds.any? { |cmd| line =~ /#{cmd}/ } + if @multiline_cmds.any? { |cmd| line =~ /#{cmd}/ } longline = [] combine = true end diff --git a/spec/unit/rbeapi/switchconfig_spec.rb b/spec/unit/rbeapi/switchconfig_spec.rb index 3038620..e509d0c 100644 --- a/spec/unit/rbeapi/switchconfig_spec.rb +++ b/spec/unit/rbeapi/switchconfig_spec.rb @@ -54,12 +54,22 @@ EOF ! +router ospf 1 + !! this + !! is a + !! routing + !! instance comment + !! that ends hereEOF + redistribute static + max-lsa 12000 +! EOS # rubocop:enable Style/TrailingWhitespace test_config_global = [ 'vlan 100', 'interface Ethernet 2', - "banner motd\nThis is my \n multiline\n banner\nends here\n\nEOF"] + "banner motd\nThis is my \n multiline\n banner\nends here\n\nEOF", + 'router ospf 1'] cmds = [' switchport mode trunk', ' switchport trunk allowed vlan 100,200'] @@ -96,7 +106,7 @@ expect(sc.line).to eq('') expect(sc.parent).to eq(nil) expect(sc.cmds).to eq(test_config_global) - expect(sc.children.length).to eq(1) + expect(sc.children.length).to eq(2) # Validate the children of global expect(sc.children[0].line).to eq(test_config_global[1]) @@ -148,6 +158,14 @@ ends here EOF +router ospf 1 + !! this + !! is a + !! routing + !! instance comment + !! that ends hereEOF + redistribute static + max-lsa 12000 EOS # rubocop:enable Style/TrailingWhitespace sw_config = Rbeapi::SwitchConfig::SwitchConfig.new(conf) @@ -174,17 +192,30 @@ ends here EOF +! +router ospf 1 + !! this + !! is a + !! routing + !! instance comment + !! that ends here + redistribute static + max-lsa 12000 EOS # rubocop:enable Style/TrailingWhitespace org_new_diff = <<-EOS vlan 100 interface Ethernet 2 switchport trunk allowed vlan 100,200 +router ospf 1 + !! that ends hereEOF EOS new_org_diff = <<-EOS vlan 101 interface Ethernet 2 switchport trunk allowed vlan 101,200 +router ospf 1 + !! that ends here EOS swc_new = Rbeapi::SwitchConfig::SwitchConfig.new(new_conf) swc_org_new = Rbeapi::SwitchConfig::SwitchConfig.new(org_new_diff) From 0d756830bce71d3de52c9cc74f4cd2abe9f51597 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Tue, 20 Sep 2016 11:23:43 -0400 Subject: [PATCH 44/60] Update returns section of get_config docs --- lib/rbeapi/client.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/client.rb b/lib/rbeapi/client.rb index 491dd14..0817735 100644 --- a/lib/rbeapi/client.rb +++ b/lib/rbeapi/client.rb @@ -506,7 +506,8 @@ def run_commands(commands, opts = {}) # interfaces Filter config to include only the given interfaces # section Display sections containing matching commands # - # @return [String] The specified configuration as text. + # @return [String] The specified configuration as text or nil if no + # config is found. def get_config(opts = {}) config = opts.fetch(:config, 'running-config') params = opts.fetch(:params, '') From d1e3679590887d1890560d4bae200c3f3d5cfce1 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Tue, 20 Sep 2016 16:30:27 -0400 Subject: [PATCH 45/60] Handle more multiline config commands --- lib/rbeapi/switchconfig.rb | 7 +-- spec/unit/rbeapi/switchconfig_spec.rb | 69 ++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/lib/rbeapi/switchconfig.rb b/lib/rbeapi/switchconfig.rb index 8ff0ce9..17fc2f6 100644 --- a/lib/rbeapi/switchconfig.rb +++ b/lib/rbeapi/switchconfig.rb @@ -214,7 +214,8 @@ class SwitchConfig # @return [Section] Returns an instance of Section def initialize(config) @indent = 3 - @multiline_cmds = ['^banner'] + @multiline_cmds = ['^banner', '^\s*ssl key', '^\s*ssl certificate', + '^\s*protocol https certificate'] chk_format(config) parse(config) end @@ -233,7 +234,7 @@ def chk_format(config) config.each_line do |line| skip = true if @multiline_cmds.any? { |cmd| line =~ /#{cmd}/ } if skip - if line =~ /^EOF$/ + if line =~ /^\s*EOF$/ skip = false else next @@ -276,7 +277,7 @@ def parse(config) end if combine longline << line - if line =~ /^EOF$/ + if line =~ /^\s*EOF$/ line = longline.join combine = false else diff --git a/spec/unit/rbeapi/switchconfig_spec.rb b/spec/unit/rbeapi/switchconfig_spec.rb index e509d0c..0a88ceb 100644 --- a/spec/unit/rbeapi/switchconfig_spec.rb +++ b/spec/unit/rbeapi/switchconfig_spec.rb @@ -54,6 +54,9 @@ EOF ! +username fred privilege 0 role network-operator secret 5 $1$u4TDdWKN$VC7cZmeGn/sgNM0RMNwhR. +username fred sshkey ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtrjGuhFeJz76Z5f3perh/R2s8XmnPcWF1uByHOqDDp53bggS9CZ7n67/QYVjbhyP70HMxY8R5Z4AevNtZTnSUQZmEgnuHvvAGNC63qrItE1i/sXKLvB1r8v0plcK35laNvJMYqGcGpjQ7T4Ufmn54zssiq1CBx6GfEX0+zKWD/5vnVDH9MMDolawILFb2a67VngzEZ0BCeRgLTg2ZEEEQt2hEKdglx87GBf7UIBFYM5xvywZRzHWta0dO1WDXCLD67kdqP52zucFXo7U3EUK/8X9Qltg5Pjr4mxf/U+hbO/K7xZJ+neAJDYA7bSXh8LkCuz00VxI5mAwo2PRMKaSp fred@localhost +! router ospf 1 !! this !! is a @@ -63,13 +66,34 @@ redistribute static max-lsa 12000 ! +management cim-provider + ssl certificate + -----BEGIN CERTIFICATE----- + MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD + r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0 + -----END CERTIFICATE----- + -----BEGIN PRIVATE KEY----- + MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR + rdPUV9/uQkdx8VrShxlD8A== + -----END PRIVATE KEY----- + EOF + ssl key + -----BEGIN PRIVATE KEY----- + MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR + rdPUV9/uQkdx8VrShxlD8A== + -----END PRIVATE KEY----- + EOF +! EOS # rubocop:enable Style/TrailingWhitespace test_config_global = [ 'vlan 100', 'interface Ethernet 2', "banner motd\nThis is my \n multiline\n banner\nends here\n\nEOF", - 'router ospf 1'] + 'username fred privilege 0 role network-operator secret 5 $1$u4TDdWKN$VC7cZmeGn/sgNM0RMNwhR.', + 'username fred sshkey ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtrjGuhFeJz76Z5f3perh/R2s8XmnPcWF1uByHOqDDp53bggS9CZ7n67/QYVjbhyP70HMxY8R5Z4AevNtZTnSUQZmEgnuHvvAGNC63qrItE1i/sXKLvB1r8v0plcK35laNvJMYqGcGpjQ7T4Ufmn54zssiq1CBx6GfEX0+zKWD/5vnVDH9MMDolawILFb2a67VngzEZ0BCeRgLTg2ZEEEQt2hEKdglx87GBf7UIBFYM5xvywZRzHWta0dO1WDXCLD67kdqP52zucFXo7U3EUK/8X9Qltg5Pjr4mxf/U+hbO/K7xZJ+neAJDYA7bSXh8LkCuz00VxI5mAwo2PRMKaSp fred@localhost', + 'router ospf 1', + 'management cim-provider'] cmds = [' switchport mode trunk', ' switchport trunk allowed vlan 100,200'] @@ -106,7 +130,7 @@ expect(sc.line).to eq('') expect(sc.parent).to eq(nil) expect(sc.cmds).to eq(test_config_global) - expect(sc.children.length).to eq(2) + expect(sc.children.length).to eq(3) # Validate the children of global expect(sc.children[0].line).to eq(test_config_global[1]) @@ -158,6 +182,8 @@ ends here EOF +username fred privilege 0 role network-operator secret 5 $1$u4TDdWKN$VC7cZmeGn/sgNM0RMNwhR. +username fred sshkey ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtrjGuhFeJz76Z5f3perh/R2s8XmnPcWF1uByHOqDDp53bggS9CZ7n67/QYVjbhyP70HMxY8R5Z4AevNtZTnSUQZmEgnuHvvAGNC63qrItE1i/sXKLvB1r8v0plcK35laNvJMYqGcGpjQ7T4Ufmn54zssiq1CBx6GfEX0+zKWD/5vnVDH9MMDolawILFb2a67VngzEZ0BCeRgLTg2ZEEEQt2hEKdglx87GBf7UIBFYM5xvywZRzHWta0dO1WDXCLD67kdqP52zucFXo7U3EUK/8X9Qltg5Pjr4mxf/U+hbO/K7xZJ+neAJDYA7bSXh8LkCuz00VxI5mAwo2PRMKaSp fred@localhost router ospf 1 !! this !! is a @@ -166,6 +192,24 @@ !! that ends hereEOF redistribute static max-lsa 12000 +! +management cim-provider + ssl certificate + -----BEGIN CERTIFICATE----- + MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD + r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0 + -----END CERTIFICATE----- + -----BEGIN PRIVATE KEY----- + MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR + rdPUV9/uQkdx8VrShxlD8A== + -----END PRIVATE KEY----- + EOF + ssl key + -----BEGIN PRIVATE KEY----- + MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR + rdPUV9/uQkdx8VrShxlD8A== + -----END PRIVATE KEY----- + EOF EOS # rubocop:enable Style/TrailingWhitespace sw_config = Rbeapi::SwitchConfig::SwitchConfig.new(conf) @@ -193,6 +237,9 @@ EOF ! +username fred privilege 0 role network-operator secret 5 $1$u4TDdWKN$VC7cZmeGn/sgNM0RMNwhR. +username fred sshkey ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtrjGuhFeJz76Z5f3perh/R2s8XmnPcWF1uByHOqDDp53bggS9CZ7n67/QYVjbhyP70HMxY8R5Z4AevNtZTnSUQZmEgnuHvvAGNC63qrItE1i/sXKLvB1r8v0plcK35laNvJMYqGcGpjQ7T4Ufmn54zssiq1CBx6GfEX0+zKWD/5vnVDH9MMDolawILFb2a67VngzEZ0BCeRgLTg2ZEEEQt2hEKdglx87GBf7UIBFYM5xvywZRzHWta0dO1WDXCLD67kdqP52zucFXo7U3EUK/8X9Qltg5Pjr4mxf/U+hbO/K7xZJ+neAJDYA7bSXh8LkCuz00VxI5mAwo2PRMKaSp fred@localhost +! router ospf 1 !! this !! is a @@ -201,6 +248,24 @@ !! that ends here redistribute static max-lsa 12000 +! +management cim-provider + ssl certificate + -----BEGIN CERTIFICATE----- + MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD + r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0 + -----END CERTIFICATE----- + -----BEGIN PRIVATE KEY----- + MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR + rdPUV9/uQkdx8VrShxlD8A== + -----END PRIVATE KEY----- + EOF + ssl key + -----BEGIN PRIVATE KEY----- + MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR + rdPUV9/uQkdx8VrShxlD8A== + -----END PRIVATE KEY----- + EOF EOS # rubocop:enable Style/TrailingWhitespace org_new_diff = <<-EOS From 8139abb44ebb2d3d250966a78056e65cfccdabbf Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 11:48:58 -0400 Subject: [PATCH 46/60] bump version --- Gemfile | 2 +- lib/rbeapi/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 8d4e4c2..1ccdebf 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,7 @@ group :development, :test do gem 'pry', require: false gem 'pry-doc', require: false gem 'pry-stack_explorer', require: false - gem 'rbeapi', '0.5.1', path: '.' + gem 'rbeapi', '1.0', path: '.' gem 'ci_reporter_rspec', require: false gem 'simplecov-json', require: false gem 'simplecov-rcov', require: false diff --git a/lib/rbeapi/version.rb b/lib/rbeapi/version.rb index da3475c..9640a4c 100644 --- a/lib/rbeapi/version.rb +++ b/lib/rbeapi/version.rb @@ -33,5 +33,5 @@ # # # Rbeapi toplevel namespace. module Rbeapi - VERSION = '0.5.1' + VERSION = '1.0' end From 801f196900d9be6c996a8213e056edb327e9f1fd Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 11:49:19 -0400 Subject: [PATCH 47/60] Add changes for v1.0 --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4ea109..a709a53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ Ruby Client for eAPI ==================== +## [v1.0](https://github.com/arista-eosplus/rbeapi/releases/tag/v1.0), September, 2016 + +[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.5.1...v1.0) + +Changes to API: +- Fix issues setting interface speeds. Speed is now returned as a string + instead of a list. ([rknaus](https://github.com/rknaus)) + +Enhancements and Fixes: +- Added set_trunk_group method to vlans API +- Fix #118 SWIX package uninstall issue +- Fix #123 which could return incorrect value for iprouting when VRFs are + enabled +- Limit several rubygem deps when testing with Ruby 1.9 +- Add load-interval option in ipinterfaces + ([n1cn0c](https://github.com/n1cn0c)) +- Fix #142 parsing of VxLAN interface multicast group parsing + ([mrvinti](https://github.com/mrvinti)) +- Improve spanning-tree MST handling ([rknaus](https://github.com/rknaus)) +- Add rbeapi/switchconfig to do block-by-block comparisons of EOS configs. This + enables configuration management tools like Chef and Puppet to take a current + and proposed running-config as a text blob and easily determine if they + differ. +- Add swix packaging of rbeapi rubygems for use with Chef-client on EOS +- Ensure that get_config, node.running_config, and node_startup_config return + sane value even when a config does not exist. + ## v0.5.1, February, 2016 - Fix issue where vlans API was not returning all configured vlan trunk_groups. From b3fea3d0f4a81cc5e2df389a42c6be9039695353 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 11:49:56 -0400 Subject: [PATCH 48/60] Update version, Puppet naming, and add Chef --- README.md | 104 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index be522c3..cbf0c79 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,28 @@ Unit/System spec/coverage: [![Spec Build Status](https://revproxy.arista.com/eos # Overview -The Ruby Client for eAPI provides a native Ruby implementation for programming Arista EOS network devices using Ruby. The Ruby client provides the ability to build native applications in Ruby that can communicate with EOS either locally via Unix domain sockets (on-box) or remotely over a HTTP/S transport (off-box). It uses a standard INI-style configuration file to specifiy one or more connection profiles. - -The rbeapi implemenation also provides an API layer for building native Ruby objects that allow for configuration and state extraction of EOS nodes. The API layer provides a consistent implementation for working with EOS configuration resources. The implementation of the API layer is highly extensible and can be used as a foundation for building custom data models. - -The libray is freely provided to the open source community for building robust applications using Arista EOS eAPI. Support is provided as best effort through Github iusses. +The Ruby Client for eAPI provides a native Ruby implementation for programming +Arista EOS network devices using Ruby. The Ruby client provides the ability to +build native applications in Ruby that can communicate with EOS either locally +via Unix domain sockets (on-box) or remotely over a HTTP/S transport (off-box). +It uses a standard INI-style configuration file to specifiy one or more +connection profiles. + +The rbeapi implemenation also provides an API layer for building native Ruby +objects that allow for configuration and state extraction of EOS nodes. The +API layer provides a consistent implementation for working with EOS +configuration resources. The implementation of the API layer is highly +extensible and can be used as a foundation for building custom data models. + +The libray is freely provided to the open source community for building robust +applications using Arista EOS eAPI. Support is provided as best effort through +Github iusses. ## Requirements * Arista EOS 4.12 or later -* Arista eAPI enabled for at least one transport (see official EOS Config Guide at arista.com for details) +* Arista eAPI enabled for at least one transport (see official EOS Config Guide + at arista.com for details) * Ruby 1.9.3 or later # Getting Started @@ -152,7 +164,7 @@ node.config('hostname veos01') node.config(['interface Ethernet1', 'description foo']) => [{}, {}] -# return the running or startup configuration from the node (output omitted for brevity) +# return the running or startup configuration from the node as a string (output omitted for brevity) node.running_config @@ -214,17 +226,18 @@ and uploaded to [RubyGems](https://rubygems.org/). ``` * To create an RPM, run ``rake rpm`` -* To generate a SWIX file for EOS with necessary dependencies, run - ``rake all_rpms`` then follow the ``swix create`` instructions, provided - by the build. NOTE: - [PuppetLabs](https://puppetlabs.com/misc/pe-files) provides a puppet agent SWIX which includes Ruby 1.9.3 in - /opt/puppet/bin/ which is different from where you might otherwise install - Ruby. If you have installed the puppet-enterprise 3.x SWIX, then you should - build and use the ``rbeapi-puppet3`` swix, below. If you have installed - the puppet-enterprise 2015.x SWIX, then you should build and use the - ``rbeapi-puppet-aio`` swix, below. Otherwise, if you have installed at least - Ruby 1.9.3 in the standard system location, then the ``rbeapi`` SWIX may be - used. +* To generate a SWIX file for EOS with necessary dependencies, run ``rake + all_rpms`` then follow the ``swix create`` instructions, provided by the +build. NOTE: [Puppet](https://puppet.com/misc/pe-files) provides a puppet +agent SWIX which includes Ruby in /opt/puppet/bin/, or /opt/puppetlabs/bin/, +which is different from where you might otherwise install Ruby. If you have +installed the puppet-enterprise 3.x SWIX, then you should build and use the +``rbeapi-puppet3`` swix, below. If you have installed the puppet-enterprise +2015.x SWIX, or higher, (the all-in-one agent) then you should build and use +the ``rbeapi-puppet-aio`` swix, below. Chef includes its own Ruby in the +omnibus installation package in /opt/chef/bin/. For Chef, use the +``rbeapi-chef`` SWIX package. Otherwise, if you have installed at least Ruby +1.9.3 in the standard system location, then the ``rbeapi`` SWIX may be used. ``` $ bundle install --path .bundle/gems/ @@ -235,21 +248,21 @@ Copy the RPMs to an EOS device then run the 'swix create' command. Examples: Puppet Open Source: cd /mnt/flash; \ - swix create rbeapi-0.5.1-1.swix \ - rubygem-rbeapi-0.5.1-1.eos4.noarch.rpm \ + swix create rbeapi-1.0-1.swix \ + rubygem-rbeapi-1.0-1.eos4.noarch.rpm \ rubygem-inifile-3.0.0-3.eos4.noarch.rpm \ rubygem-netaddr-1.5.0-2.eos4.noarch.rpm \ rubygem-net_http_unix-0.2.1-3.eos4.noarch.rpm Puppet-enterprise agent (3.x): cd/mnt/flash; \ - swix create rbeapi-puppet3-0.5.1-1.swix \ - rubygem-rbeapi-puppet3-0.5.1-1.eos4.noarch.rpm \ + swix create rbeapi-puppet3-1.0-1.swix \ + rubygem-rbeapi-puppet3-1.0-1.eos4.noarch.rpm \ rubygem-inifile-puppet3-3.0.0-3.eos4.noarch.rpm \ rubygem-netaddr-puppet3-1.5.0-2.eos4.noarch.rpm Puppet-All-in-one agent (2015.x/4.x): cd/mnt/flash; \ - swix create rbeapi-puppet-aio-0.5.1-1.swix \ - rubygem-rbeapi-puppet-aio-0.5.1-1.eos4.noarch.rpm \ + swix create rbeapi-puppet-aio-1.0-1.swix \ + rubygem-rbeapi-puppet-aio-1.0-1.eos4.noarch.rpm \ rubygem-inifile-puppet-aio-3.0.0-3.eos4.noarch.rpm \ rubygem-netaddr-puppet-aio-1.5.0-2.eos4.noarch.rpm \ rubygem-net_http_unix-puppet-aio-0.2.1-3.eos4.noarch.rpm @@ -260,13 +273,13 @@ Copy the RPMs to an EOS device then run the 'swix create' command. Arista# copy flash: Arista# bash -bash-4.1# cd /mnt/flash/ - -bash-4.1# swix create rbeapi-puppet3-0.5.1-1.swix \ - rubygem-rbeapi-puppet3-0.5.1-1.eos4.noarch.rpm \ + -bash-4.1# swix create rbeapi-puppet3-1.0-1.swix \ + rubygem-rbeapi-puppet3-1.0-1.eos4.noarch.rpm \ rubygem-inifile-puppet3-3.0.0-1.eos4.noarch.rpm \ rubygem-netaddr-puppet3-1.5.0-1.eos4.noarch.rpm -bash-4.1# exit - Arista# copy flash:rbeapi-puppet3-0.5.1-1.swix extension: - Arista# extension rbeapi-puppet3-0.5.1-1.swix + Arista# copy flash:rbeapi-puppet3-1.0-1.swix extension: + Arista# extension rbeapi-puppet3-1.0-1.swix Arista# copy installed-extensions boot-extensions ``` @@ -275,7 +288,7 @@ Copy the RPMs to an EOS device then run the 'swix create' command. On EOS: ``` Arista# no extension pe-rbeapi-0.3.0-1.swix - Arista# extension rbeapi-puppet3-0.5.1-1.swix + Arista# extension rbeapi-puppet3-1.0-1.swix Arista# copy installed-extensions boot-extensions ``` @@ -298,12 +311,27 @@ corresponding test cases otherwise the pull request will be rejected. Copyright (c) 2016, Arista Networks, Inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -Neither the name of Arista Networks nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Arista Networks nor the names of its contributors may be +used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 571c5d73cb35a087e12f5551477f80ff3330bdb3 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 12:00:14 -0400 Subject: [PATCH 49/60] Add Chef swix build example --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index cbf0c79..88f6d4f 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,14 @@ Copy the RPMs to an EOS device then run the 'swix create' command. rubygem-inifile-puppet-aio-3.0.0-3.eos4.noarch.rpm \ rubygem-netaddr-puppet-aio-1.5.0-2.eos4.noarch.rpm \ rubygem-net_http_unix-puppet-aio-0.2.1-3.eos4.noarch.rpm + + Chef client: + cd /mnt/flash; \ + swix create rbeapi-chef-1.0-1.swix \ + rubygem-rbeapi-chef-1.0-1.eos4.noarch.rpm \ + rubygem-inifile-chef-3.0.0-5.eos4.noarch.rpm \ + rubygem-netaddr-chef-1.5.1-4.eos4.noarch.rpm \ + rubygem-net_http_unix-chef-0.2.2-5.eos4.noarch.rpm ``` On EOS: From 4ad0246f733ec4a9ab3af3ea8575a57907d1e39f Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 13:32:04 -0400 Subject: [PATCH 50/60] Update formatting on guide pages --- guide/getting-started.rst | 10 +++++++++- guide/installation.rst | 22 +++++++++++++++++++--- guide/testing.rst | 7 +++++-- guide/upgrading.rst | 2 ++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/guide/getting-started.rst b/guide/getting-started.rst index 8420889..e17178a 100644 --- a/guide/getting-started.rst +++ b/guide/getting-started.rst @@ -14,6 +14,7 @@ Below is an example of an eAPI conf file. The conf file can contain more than on The following configuration options are available for defining node entries: +``` host - The IP address or FQDN of the remote device. If the host parameter is omitted then the connection name is used username - The eAPI username to use for authentication (only required for http or https connections) password - The eAPI password to use for authentication (only required for http or https connections) @@ -30,11 +31,13 @@ The following configuration options are available for defining node entries: transport: socket, default port: n/a open_timeout - The default number of seconds to wait for the eAPI connection to open. Any number may be used, including Floats for fractional seconds. Default value is 10 seconds. read_timeout - The default number of seconds to wait for one block of eAPI results to be read (via one read(2) call). Any number may be used, including Floats for fractional seconds. Default value is 10 seconds. +``` Note: See the EOS User Manual found at arista.com for more details on configuring eAPI values. All configuration values are optional. +``` [connection:veos01] username: eapi password: password @@ -56,6 +59,7 @@ transport: https [connection:localhost] transport: http_local +``` The above example shows different ways to define EOS node connections. All configuration options will attempt to use default values if not explicitly defined. If the host parameter is not set for a given entry, then the connection name will be used as the host address. @@ -74,6 +78,7 @@ Creating a connection and sending commands Once EOS is configured properly and the config file created, getting started with a connection to EOS is simple. Below demonstrates a basic connection using rbeapi. For more examples, please see the examples folder. +``` # start by importing the library require 'rbeapi/client' @@ -99,12 +104,14 @@ node.config(['interface Ethernet1', 'description foo']) node.running_config node.startup_config +``` Using the API ------------- The rbeapi library provides both a client for send and receiving commands over eAPI as well as an API for working directly with EOS resources. The API is designed to be easy and straightforward to use yet also extensible. Below is an example of working with the vlans API +``` # create a connection to the node require 'rbeapi/client' node = Rbeapi::Client.connect_to('veos01') @@ -130,5 +137,6 @@ vlans.create(400) # set the new vlan name vlans.set_name(100, value: 'foo') => true +``` -All API implementations developed by Arista EOS+ CS are found in the rbeapi/api folder. See the examples folder for additional examples. \ No newline at end of file +All API implementations developed by Arista EOS+ CS are found in the rbeapi/api folder. See the examples folder for additional examples. diff --git a/guide/installation.rst b/guide/installation.rst index 792a678..e4ffb16 100644 --- a/guide/installation.rst +++ b/guide/installation.rst @@ -5,17 +5,30 @@ Installation The source code for rbeapi is provided on Github at http://github.com/arista-eosplus/rbeapi. All current development is done in the develop branch. Stable released versions are tagged in the master branch and uploaded to RubyGems. - To install the latest stable version of rbeapi, simply run gem install rbeapi + To install the latest stable version of rbeapi, simply run `gem install rbeapi`` To install the latest development version from Github, simply clone the develop branch and run + ``` $ rake build $ rake install + ``` - To create an RPM, run rake rpm + To create an RPM, run `rake rpm` - To generate a SWIX file for EOS with necessary dependencies, run rake all_rpms then follow the swix create instructions, provided by the build. NOTE: PuppetLabs provides a puppet agent SWIX which includes Ruby 1.9.3 in /opt/puppet/bin/ which is different from where you might otherwise install Ruby. If you have installed the puppet-enterprise 3.x SWIX, then you should build and use the rbeapi-puppet3 swix, below. If you have installed the puppet-enterprise 2015.x SWIX, then you should build and use the rbeapi-puppet-aio swix, below. Otherwise, if you have installed at least Ruby 1.9.3 in the standard system location, then the rbeapi SWIX may be used. + To generate a SWIX file for EOS with necessary dependencies, run `rake + all_rpms` then follow the swix create instructions, provided by the build. + NOTE: Puppet provides a puppet agent SWIX which includes Ruby 1.9.3 in + /opt/puppetlabs/bin/ which is different from where you might otherwise + install Ruby. If you have installed the puppet-enterprise 3.x SWIX, then + you should build and use the rbeapi-puppet3 swix, below. If you have + installed the puppet-enterprise 2015.x SWIX, then you should build and use + the rbeapi-puppet-aio swix, below. The Chef client omnibus install also + includes its own version of Ruby in /opt/chef/bin/, thus the rbeapi-chef + swix should be used. Otherwise, if you have installed at least Ruby + 1.9.3 in the standard system location, then the rbeapi SWIX may be used. + ``` $ bundle install --path .bundle/gems/ $ bundle exec rake all_rpms ... @@ -42,9 +55,11 @@ The source code for rbeapi is provided on Github at http://github.com/arista-eos rubygem-inifile-puppet-aio-3.0.0-3.eos4.noarch.rpm \ rubygem-netaddr-puppet-aio-1.5.0-2.eos4.noarch.rpm \ rubygem-net_http_unix-puppet-aio-0.2.1-3.eos4.noarch.rpm + ``` On EOS: + ``` Arista# copy flash: Arista# bash -bash-4.1# cd /mnt/flash/ @@ -56,4 +71,5 @@ The source code for rbeapi is provided on Github at http://github.com/arista-eos Arista# copy flash:rbeapi-puppet3-0.4.0-1.swix extension: Arista# extension rbeapi-puppet3-0.4.0-1.swix Arista# copy installed-extensions boot-extensions + ``` diff --git a/guide/testing.rst b/guide/testing.rst index d28b5c4..12dfd16 100644 --- a/guide/testing.rst +++ b/guide/testing.rst @@ -3,6 +3,9 @@ Testing Modules .. contents:: :local: -The rbeapi library provides spec tests. To run the spec tests, you will need to update the dut.conf file found in spec/fixtures. The switch used for testing should have at least interfaces Ethernet1-7. +The rbeapi library provides spec tests. To run the spec tests, you will need to +update the `spec/fixtures/dut.conf` file. The switch used for testing +must have at least interfaces Ethernet1-7. - To run the spec tests, run bundle exec rspec spec from the root of the rbeapi source folder. +To run the spec tests, run `bundle exec rspec spec` from the root of the +rbeapi source folder. diff --git a/guide/upgrading.rst b/guide/upgrading.rst index 1467255..e45fb64 100644 --- a/guide/upgrading.rst +++ b/guide/upgrading.rst @@ -5,6 +5,8 @@ Upgrading On EOS: +``` Arista# no extension pe-rbeapi-0.3.0-1.swix Arista# extension rbeapi-puppet3-0.4.0-1.swix Arista# copy installed-extensions boot-extensions +``` From 24e9c22ff6b564294d873f2869b45b976c039cc1 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 13:51:51 -0400 Subject: [PATCH 51/60] Update formatting on guide pages --- guide/getting-started.rst | 167 ++++++++++++++++++++++---------------- guide/installation.rst | 31 ++++--- guide/testing.rst | 4 +- guide/upgrading.rst | 4 +- 4 files changed, 117 insertions(+), 89 deletions(-) diff --git a/guide/getting-started.rst b/guide/getting-started.rst index e17178a..b3b5bdb 100644 --- a/guide/getting-started.rst +++ b/guide/getting-started.rst @@ -3,18 +3,26 @@ Getting Started .. contents:: :local: -In order to use rbeapi, the EOS command API must be enabled using management api http-commands configuration mode. This library supports eAPI calls over both HTTP and UNIX Domain Sockets. Once the command API is enabled on the destination node, create a configuration file with the node properities. +In order to use rbeapi, the EOS command API must be enabled using management +api http-commands configuration mode. This library supports eAPI calls over +both HTTP and UNIX Domain Sockets. Once the command API is enabled on the +destination node, create a configuration file with the node properities. -Note: The default search path for the conf file is ~/.eapi.conf followed by /mnt/flash/eapi.conf. This can be overridden by setting EAPI_CONF= in your environment. +Note: The default search path for the conf file is ``~/.eapi.conf`` followed by +``/mnt/flash/eapi.conf``. This can be overridden by setting +``EAPI_CONF=`` in your environment. Example eapi.conf File ---------------------- -Below is an example of an eAPI conf file. The conf file can contain more than one node. Each node section must be prefaced by connection: where is the name of the connection. +Below is an example of an eAPI conf file. The conf file can contain more than +one node. Each node section must be prefaced by connection: where +is the name of the connection. The following configuration options are available for defining node entries: -``` +.. code-block:: console + host - The IP address or FQDN of the remote device. If the host parameter is omitted then the connection name is used username - The eAPI username to use for authentication (only required for http or https connections) password - The eAPI password to use for authentication (only required for http or https connections) @@ -31,112 +39,127 @@ The following configuration options are available for defining node entries: transport: socket, default port: n/a open_timeout - The default number of seconds to wait for the eAPI connection to open. Any number may be used, including Floats for fractional seconds. Default value is 10 seconds. read_timeout - The default number of seconds to wait for one block of eAPI results to be read (via one read(2) call). Any number may be used, including Floats for fractional seconds. Default value is 10 seconds. -``` -Note: See the EOS User Manual found at arista.com for more details on configuring eAPI values. +Note: See the EOS User Manual found at arista.com for more details on +configuring eAPI values. All configuration values are optional. -``` -[connection:veos01] -username: eapi -password: password -transport: http +.. code-block:: console + + [connection:veos01] + username: eapi + password: password + transport: http -[connection:veos02] -transport: http + [connection:veos02] + transport: http -[connection:veos03] -transport: socket + [connection:veos03] + transport: socket -[connection:veos04] -host: 172.16.10.1 -username: eapi -password: password -enablepwd: itsasecret -port: 1234 -transport: https + [connection:veos04] + host: 172.16.10.1 + username: eapi + password: password + enablepwd: itsasecret + port: 1234 + transport: https -[connection:localhost] -transport: http_local -``` + [connection:localhost] + transport: http_local -The above example shows different ways to define EOS node connections. All configuration options will attempt to use default values if not explicitly defined. If the host parameter is not set for a given entry, then the connection name will be used as the host address. +The above example shows different ways to define EOS node connections. All +configuration options will attempt to use default values if not explicitly +defined. If the host parameter is not set for a given entry, then the +connection name will be used as the host address. Configuring [connection:localhost] ---------------------------------- -The rbeapi library automatically installs a single default configuration entry for connecting to localhost host using a transport of sockets. If using the rbeapi library locally on an EOS node, simply enable the command API to use sockets and no further configuration is needed for rbeapi to function. If you specify an entry in a conf file with the name [connection:localhost], the values in the conf file will overwrite the default. +The rbeapi library automatically installs a single default configuration entry +for connecting to localhost host using a transport of sockets. If using the +rbeapi library locally on an EOS node, simply enable the command API to use +sockets and no further configuration is needed for rbeapi to function. If you +specify an entry in a conf file with the name [connection:localhost], the +values in the conf file will overwrite the default. Using rbeapi ------------ -The Ruby Client for eAPI was designed to be easy to use and implement for writing tools and applications that interface with the Arista EOS management plane. +The Ruby Client for eAPI was designed to be easy to use and implement for +writing tools and applications that interface with the Arista EOS management +plane. Creating a connection and sending commands ------------------------------------------ -Once EOS is configured properly and the config file created, getting started with a connection to EOS is simple. Below demonstrates a basic connection using rbeapi. For more examples, please see the examples folder. +Once EOS is configured properly and the config file created, getting started +with a connection to EOS is simple. Below demonstrates a basic connection using +rbeapi. For more examples, please see the examples folder. -``` -# start by importing the library -require 'rbeapi/client' +.. code-block:: console + # start by importing the library + require 'rbeapi/client' -# create a node object by specifying the node to work with -node = Rbeapi::Client.connect_to('veos01') + # create a node object by specifying the node to work with + node = Rbeapi::Client.connect_to('veos01') -# send one or more commands to the node -node.enable('show hostname') -node.enable('show hostname') -=> [{:command=>"show hostname", :result=>{"fqdn"=>"veos01.arista.com", "hostname"=>"veos01"}, :encoding=>"json"}] + # send one or more commands to the node + node.enable('show hostname') + node.enable('show hostname') + => [{:command=>"show hostname", :result=>{"fqdn"=>"veos01.arista.com", "hostname"=>"veos01"}, :encoding=>"json"}] -# use the config method to send configuration commands -node.config('hostname veos01') -=> [{}] + # use the config method to send configuration commands + node.config('hostname veos01') + => [{}] -# multiple commands can be sent by using a list (works for both enable or config) + # multiple commands can be sent by using a list (works for both enable or config) -node.config(['interface Ethernet1', 'description foo']) -=> [{}, {}] + node.config(['interface Ethernet1', 'description foo']) + => [{}, {}] -# return the running or startup configuration from the node (output omitted for brevity) + # return the running or startup configuration from the node (output omitted for brevity) -node.running_config + node.running_config -node.startup_config -``` + node.startup_config Using the API ------------- -The rbeapi library provides both a client for send and receiving commands over eAPI as well as an API for working directly with EOS resources. The API is designed to be easy and straightforward to use yet also extensible. Below is an example of working with the vlans API +The rbeapi library provides both a client for send and receiving commands over +eAPI as well as an API for working directly with EOS resources. The API is +designed to be easy and straightforward to use yet also extensible. Below is an +example of working with the vlans API + +.. code-block:: console -``` -# create a connection to the node -require 'rbeapi/client' -node = Rbeapi::Client.connect_to('veos01') + # create a connection to the node + require 'rbeapi/client' + node = Rbeapi::Client.connect_to('veos01') -# get the instance of the API (in this case vlans) -vlans = node.api('vlans') + # get the instance of the API (in this case vlans) + vlans = node.api('vlans') -# return all vlans from the node -vlans.getall -=> {"1"=>{:name=>"tester", :state=>"active", :trunk_groups=>[]}, - "4"=>{:name=>"VLAN0004", :state=>"active", :trunk_groups=>[]}, - "100"=>{:name=>"TEST_VLAN_100", :state=>"active", :trunk_groups=>[]}, - "300"=>{:name=>"VLAN0300", :state=>"active", :trunk_groups=>[]}} + # return all vlans from the node + vlans.getall + => {"1"=>{:name=>"tester", :state=>"active", :trunk_groups=>[]}, + "4"=>{:name=>"VLAN0004", :state=>"active", :trunk_groups=>[]}, + "100"=>{:name=>"TEST_VLAN_100", :state=>"active", :trunk_groups=>[]}, + "300"=>{:name=>"VLAN0300", :state=>"active", :trunk_groups=>[]}} -# return a specific vlan from the node -vlans.get(1) -=> {:name=>"tester", :state=>"active", :trunk_groups=>[]} + # return a specific vlan from the node + vlans.get(1) + => {:name=>"tester", :state=>"active", :trunk_groups=>[]} -# add a new vlan to the node -vlans.create(400) -=> true + # add a new vlan to the node + vlans.create(400) + => true -# set the new vlan name -vlans.set_name(100, value: 'foo') -=> true -``` + # set the new vlan name + vlans.set_name(100, value: 'foo') + => true -All API implementations developed by Arista EOS+ CS are found in the rbeapi/api folder. See the examples folder for additional examples. +All API implementations developed by Arista EOS+ CS are found in the rbeapi/api +folder. See the examples folder for additional examples. diff --git a/guide/installation.rst b/guide/installation.rst index e4ffb16..801465f 100644 --- a/guide/installation.rst +++ b/guide/installation.rst @@ -3,21 +3,26 @@ Installation .. contents:: :local: -The source code for rbeapi is provided on Github at http://github.com/arista-eosplus/rbeapi. All current development is done in the develop branch. Stable released versions are tagged in the master branch and uploaded to RubyGems. +The source code for rbeapi is provided on Github at +http://github.com/arista-eosplus/rbeapi. All current development is done in the +develop branch. Stable released versions are tagged in the master branch and +uploaded to RubyGems. - To install the latest stable version of rbeapi, simply run `gem install rbeapi`` +To install the latest stable version of rbeapi, simply run ``gem install +rbeapi`` - To install the latest development version from Github, simply clone the develop branch and run +To install the latest development version from Github, simply clone the develop +branch and run + +.. code-block:: console - ``` $ rake build $ rake install - ``` - To create an RPM, run `rake rpm` + To create an RPM, run ``rake rpm`` - To generate a SWIX file for EOS with necessary dependencies, run `rake - all_rpms` then follow the swix create instructions, provided by the build. + To generate a SWIX file for EOS with necessary dependencies, run ``rake + all_rpms`` then follow the swix create instructions, provided by the build. NOTE: Puppet provides a puppet agent SWIX which includes Ruby 1.9.3 in /opt/puppetlabs/bin/ which is different from where you might otherwise install Ruby. If you have installed the puppet-enterprise 3.x SWIX, then @@ -28,7 +33,8 @@ The source code for rbeapi is provided on Github at http://github.com/arista-eos swix should be used. Otherwise, if you have installed at least Ruby 1.9.3 in the standard system location, then the rbeapi SWIX may be used. - ``` +.. code-block:: console + $ bundle install --path .bundle/gems/ $ bundle exec rake all_rpms ... @@ -55,11 +61,11 @@ The source code for rbeapi is provided on Github at http://github.com/arista-eos rubygem-inifile-puppet-aio-3.0.0-3.eos4.noarch.rpm \ rubygem-netaddr-puppet-aio-1.5.0-2.eos4.noarch.rpm \ rubygem-net_http_unix-puppet-aio-0.2.1-3.eos4.noarch.rpm - ``` - On EOS: +On EOS: + +.. code-block:: console - ``` Arista# copy flash: Arista# bash -bash-4.1# cd /mnt/flash/ @@ -71,5 +77,4 @@ The source code for rbeapi is provided on Github at http://github.com/arista-eos Arista# copy flash:rbeapi-puppet3-0.4.0-1.swix extension: Arista# extension rbeapi-puppet3-0.4.0-1.swix Arista# copy installed-extensions boot-extensions - ``` diff --git a/guide/testing.rst b/guide/testing.rst index 12dfd16..9c98bb3 100644 --- a/guide/testing.rst +++ b/guide/testing.rst @@ -4,8 +4,8 @@ Testing Modules .. contents:: :local: The rbeapi library provides spec tests. To run the spec tests, you will need to -update the `spec/fixtures/dut.conf` file. The switch used for testing +update the ``spec/fixtures/dut.conf`` file. The switch used for testing must have at least interfaces Ethernet1-7. -To run the spec tests, run `bundle exec rspec spec` from the root of the +To run the spec tests, run ``bundle exec rspec spec`` from the root of the rbeapi source folder. diff --git a/guide/upgrading.rst b/guide/upgrading.rst index e45fb64..d109a71 100644 --- a/guide/upgrading.rst +++ b/guide/upgrading.rst @@ -5,8 +5,8 @@ Upgrading On EOS: -``` +.. code-block:: console + Arista# no extension pe-rbeapi-0.3.0-1.swix Arista# extension rbeapi-puppet3-0.4.0-1.swix Arista# copy installed-extensions boot-extensions -``` From 103168422e7ec8454fd8ba404f7547ba6d641db0 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 14:11:48 -0400 Subject: [PATCH 52/60] Add minimum Ruby version --- rbeapi.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rbeapi.gemspec b/rbeapi.gemspec index 14ff765..2a41479 100644 --- a/rbeapi.gemspec +++ b/rbeapi.gemspec @@ -31,4 +31,6 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rspec', '~> 3.0.0' spec.add_development_dependency 'rspec-mocks', '~> 3.0.0' spec.add_development_dependency 'simplecov' + + spec.required_ruby_version = '>= 1.9.3' end From 6e0aa4a6188b5c673ac25f7c43126916d882934a Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 14:17:10 -0400 Subject: [PATCH 53/60] Update release notes with links to GH changelog --- guide/release-notes.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/guide/release-notes.rst b/guide/release-notes.rst index 31b3783..1ff9a29 100644 --- a/guide/release-notes.rst +++ b/guide/release-notes.rst @@ -3,4 +3,8 @@ Release Notes .. toctree:: :maxdepth: 2 - :titlesonly: \ No newline at end of file + :titlesonly: + +For the most up-to-date release notes, see the `GitHub release +`_ pages or the `CHANGELOG +`_. From f62f97692806dd69ebb86cc700c8199fcb1fa205 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 14:45:37 -0400 Subject: [PATCH 54/60] Add json option to get_config --- lib/rbeapi/client.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/rbeapi/client.rb b/lib/rbeapi/client.rb index 0817735..1b4298e 100644 --- a/lib/rbeapi/client.rb +++ b/lib/rbeapi/client.rb @@ -511,9 +511,10 @@ def run_commands(commands, opts = {}) def get_config(opts = {}) config = opts.fetch(:config, 'running-config') params = opts.fetch(:params, '') + encoding = opts.fetch(:encoding, 'text') as_string = opts.fetch(:as_string, false) begin - result = run_commands("show #{config} #{params}", encoding: 'text') + result = run_commands("show #{config} #{params}", encoding: encoding) rescue Rbeapi::Eapilib::CommandError => error if ( error.to_s =~ /show (running|startup)-config/ ) return nil @@ -521,8 +522,12 @@ def get_config(opts = {}) raise error end end - return result.first['output'].strip.split("\n") unless as_string - result.first['output'].strip + if encoding == 'json' + return result.first + else + return result.first['output'].strip.split("\n") unless as_string + result.first['output'].strip + end end ## From c9ded0d92f122565c8842989a780397608abc1fb Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Wed, 21 Sep 2016 16:27:40 -0400 Subject: [PATCH 55/60] Add unit and system test targets to the Rakefile --- Rakefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Rakefile b/Rakefile index fef65db..7b4cb2e 100644 --- a/Rakefile +++ b/Rakefile @@ -170,6 +170,12 @@ task ci_spec: [:ci_prep, 'ci:setup:rspec', :spec] require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) +RSpec::Core::RakeTask.new(:unit) do |t| + t.pattern = './**/unit/**/*_spec.rb' +end +RSpec::Core::RakeTask.new(:system) do |t| + t.pattern = './**/system/**/*_spec.rb' +end desc 'Generate typedoc.rst for the guide' task :typedoc do From 70069980e11115ff9b661a1e841620b266884bd8 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 22 Sep 2016 06:15:54 -0400 Subject: [PATCH 56/60] Narrow scope of error check in get_config and add additional unittest --- lib/rbeapi/client.rb | 2 +- spec/unit/rbeapi/client_spec.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/client.rb b/lib/rbeapi/client.rb index 0817735..a119a8b 100644 --- a/lib/rbeapi/client.rb +++ b/lib/rbeapi/client.rb @@ -515,7 +515,7 @@ def get_config(opts = {}) begin result = run_commands("show #{config} #{params}", encoding: 'text') rescue Rbeapi::Eapilib::CommandError => error - if ( error.to_s =~ /show (running|startup)-config/ ) + if ( error.to_s =~ /'show (running|startup)-config'/ ) return nil else raise error diff --git a/spec/unit/rbeapi/client_spec.rb b/spec/unit/rbeapi/client_spec.rb index d583bb6..4ae262b 100644 --- a/spec/unit/rbeapi/client_spec.rb +++ b/spec/unit/rbeapi/client_spec.rb @@ -242,5 +242,13 @@ def startup_config_response allow(node).to receive(:run_commands).and_raise(Rbeapi::Eapilib::CommandError.new(msg, 1000)) expect(node.get_config()).to be_nil end + + it 'raises invalid command error' do + msg = "CLI command 2 of 2 'show startup-configurations' failed: invalid command" + allow(node).to receive(:run_commands).and_raise(Rbeapi::Eapilib::CommandError.new(msg, 1000)) + expect { node.get_config(config: 'running-configurations') } + .to raise_error Rbeapi::Eapilib::CommandError + end + end end From 6edd77e4ec22444725212f448aae88fc10a63220 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 22 Sep 2016 06:33:40 -0400 Subject: [PATCH 57/60] Update docstring --- lib/rbeapi/client.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/rbeapi/client.rb b/lib/rbeapi/client.rb index 1b4298e..9565327 100644 --- a/lib/rbeapi/client.rb +++ b/lib/rbeapi/client.rb @@ -507,7 +507,8 @@ def run_commands(commands, opts = {}) # section Display sections containing matching commands # # @return [String] The specified configuration as text or nil if no - # config is found. + # config is found. When encoding is set to json, returns + # a hash. def get_config(opts = {}) config = opts.fetch(:config, 'running-config') params = opts.fetch(:params, '') From f2e5949ce9d38ca2ddd71ce4c0e0c2b84007b893 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 22 Sep 2016 14:49:21 -0400 Subject: [PATCH 58/60] Add github_changelog_generator for releases --- Gemfile | 4 ++++ Rakefile | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1ccdebf..b0a3e5b 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,7 @@ group :development, :test do gem 'ci_reporter_rspec', require: false gem 'simplecov-json', require: false gem 'simplecov-rcov', require: false + gem 'github_changelog_generator', require: false end # Rubocop > 0.37 requires a gem that only works with ruby 2.x @@ -40,5 +41,8 @@ else gem 'rubocop', '>=0.35.1' end end +if RUBY_VERSION.to_f < 2.2 + gem 'rack', '<2.0' +end # vim:ft=ruby diff --git a/Rakefile b/Rakefile index 7b4cb2e..a0423e3 100644 --- a/Rakefile +++ b/Rakefile @@ -1,4 +1,5 @@ require 'bundler/gem_tasks' +require 'github_changelog_generator/task' $LOAD_PATH.unshift File.expand_path('../lib', __FILE__) require 'rbeapi/version' @@ -147,7 +148,11 @@ task swix: :all_rpms do puts "#\n################################################\n\n" end -task release: :build do +GitHubChangelogGenerator::RakeTask.new :changelog do |config| + config.future_release = Rbeapi::VERSION +end + +task release: [:changelog, :build] do system "gem push rbeapi-#{Rbeapi::VERSION}.gem" end From f69892e9db8a512ac1992ad4128f38eefbe16385 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Thu, 22 Sep 2016 14:50:53 -0400 Subject: [PATCH 59/60] Updated for Release 1.0 --- CHANGELOG.md | 314 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 211 insertions(+), 103 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a709a53..96bb38b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,103 +1,211 @@ -Ruby Client for eAPI -==================== - -## [v1.0](https://github.com/arista-eosplus/rbeapi/releases/tag/v1.0), September, 2016 - -[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.5.1...v1.0) - -Changes to API: -- Fix issues setting interface speeds. Speed is now returned as a string - instead of a list. ([rknaus](https://github.com/rknaus)) - -Enhancements and Fixes: -- Added set_trunk_group method to vlans API -- Fix #118 SWIX package uninstall issue -- Fix #123 which could return incorrect value for iprouting when VRFs are - enabled -- Limit several rubygem deps when testing with Ruby 1.9 -- Add load-interval option in ipinterfaces - ([n1cn0c](https://github.com/n1cn0c)) -- Fix #142 parsing of VxLAN interface multicast group parsing - ([mrvinti](https://github.com/mrvinti)) -- Improve spanning-tree MST handling ([rknaus](https://github.com/rknaus)) -- Add rbeapi/switchconfig to do block-by-block comparisons of EOS configs. This - enables configuration management tools like Chef and Puppet to take a current - and proposed running-config as a text blob and easily determine if they - differ. -- Add swix packaging of rbeapi rubygems for use with Chef-client on EOS -- Ensure that get_config, node.running_config, and node_startup_config return - sane value even when a config does not exist. - -## v0.5.1, February, 2016 - -- Fix issue where vlans API was not returning all configured vlan trunk_groups. - -## v0.5.0, January, 2016 - -- Add optional ‘mode’ parameter to set_members() method in port-channel - interfaces API -- Add support for trunk groups -- Ensure multiple connections based on the wildcard settings do not clobber - each other. -- Add ‘terminal’ to the ‘configure’ command to workaround AAA issue -- Fix issue where ‘enablepw’ in the eapi.conf was not properly used -- Catch errors and syslog them when parsing eapi conf file. - In the event of an unparsable eapi.conf, a syslog warning will be generated - but the app will continue to attempt to utilize the default localhost conn. -- Ensure that nil is returned when getting nonexistent username -- Ensure all parse methods are private -- Add tests for timeout values -- Update framework tests -- Add unit tests for switchports -- Address code coverage gaps - - -## v0.4.0, November, 2015 - -- New users API -- New routemap API -- New vrrp API -- BGP API: Add support for maximum_paths and maximum_ecmp_paths -- System API: add support for managing the global EOS ‘ip routing’ setting -- Updated RPM/SWIX packaging to handle Puppet All-In-One (AIO) agent paths - New package names are: rbeapi, rbeapi-puppet3 (formerly pe-puppet), - and rbeapi-puppet-aio -- Fixed port-channel get_members() issue with EOS 4.15 and above. -- Fixed issue with the eapi.conf wildcard connection -- Fixed issue that would cause a traceback when searching for eapi.conf if - $HOME was not set - - -## v0.3.0, August, 2015 - -- API Change: Eliminated overloading the value option in command_builder. When - the value is set it is used as a value in building the command. When the value - is false then the command is negated. This doesn’t allow a value to be - specified when the command is negated. -- APIs updated to take advantage of command_builder() -- Add staticroutes API -- Fix issue which would cause the module to fail to load when $HOME was not set -- Fix builds (all_rpms) to work on Ubuntu -- Fix rbeapi rubygem RPM requires - -## v0.2.0, July, 2015 - -- Change the default transport to https -- Add new dependency: rubygem-netaddr -- Add [api.acl] with support for standard ACLs -- Add capability to build all necessary RPMS for EOS from the Rakefile -- Add `[connection:*]` syntax to eapi.conf to provide defaults for unspecified hosts -- Add configurable read and open timeouts -- Add new methods to the Entity class -- Add new VNI mapping to VxLan interface -- Add port-fast support to [api.stp] -- Fix issue with sending calls to interface instance by name -- Fix [api.vlans] issue parsing vlan name with a `-` character -- Fix issue where [api.interfaces] could return duplicate port-channel members on MLAG interfaces -- Fix missing OpenSSL require -- Fix Rubocop warnings - - -## v0.1.0, 2/25/2015 - -- Initial public release of rbeapi +# Change Log + +## [1.0](https://github.com/arista-eosplus/rbeapi/tree/1.0) (2016-09-22) +[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.5.1...1.0) + +**Implemented enhancements:** + +- Need to validate value keyword in set methods when array [\#40](https://github.com/arista-eosplus/rbeapi/issues/40) +- Limit rubocop version when running ruby 1.9 [\#125](https://github.com/arista-eosplus/rbeapi/pull/125) ([jerearista](https://github.com/jerearista)) + +**Fixed bugs:** + +- the "running\_config" api error [\#127](https://github.com/arista-eosplus/rbeapi/issues/127) +- system API may return incorrect value for iprouting when VRF present [\#123](https://github.com/arista-eosplus/rbeapi/issues/123) +- SWIX does not uninstall cleanly [\#118](https://github.com/arista-eosplus/rbeapi/issues/118) +- vlans API only returns first trunk\_group [\#113](https://github.com/arista-eosplus/rbeapi/issues/113) +- Bugfix - system :iprouting only picks up global ip routing, ignoring VRFs [\#124](https://github.com/arista-eosplus/rbeapi/pull/124) ([jerearista](https://github.com/jerearista)) + +**Closed issues:** + +- multicast group parsing for vxlan interfaces fails [\#142](https://github.com/arista-eosplus/rbeapi/issues/142) +- Should switchconfig inject exit command at end of a section \(child\)? [\#136](https://github.com/arista-eosplus/rbeapi/issues/136) +- SwitchConfig parse needs to account for irregular spacing in config banner [\#135](https://github.com/arista-eosplus/rbeapi/issues/135) + +**Merged pull requests:** + +- Add json option to get\_config [\#151](https://github.com/arista-eosplus/rbeapi/pull/151) ([jerearista](https://github.com/jerearista)) +- Handle more multiline config commands [\#150](https://github.com/arista-eosplus/rbeapi/pull/150) ([jerearista](https://github.com/jerearista)) +- Ensure get\_config, running\_config, and startup\_config return sane output [\#149](https://github.com/arista-eosplus/rbeapi/pull/149) ([jerearista](https://github.com/jerearista)) +- Switchconfig: handle non-standard indentation on banners [\#148](https://github.com/arista-eosplus/rbeapi/pull/148) ([jerearista](https://github.com/jerearista)) +- add spec tests for prefix lists [\#147](https://github.com/arista-eosplus/rbeapi/pull/147) ([mrvinti](https://github.com/mrvinti)) +- Add switchconfig feature [\#146](https://github.com/arista-eosplus/rbeapi/pull/146) ([jerearista](https://github.com/jerearista)) +- Fix test issues [\#145](https://github.com/arista-eosplus/rbeapi/pull/145) ([jerearista](https://github.com/jerearista)) +- fix parse\_instances to return the default instances and add tests [\#144](https://github.com/arista-eosplus/rbeapi/pull/144) ([rknaus](https://github.com/rknaus)) +- fix issue \#142 - multicast group parsing when not configured [\#143](https://github.com/arista-eosplus/rbeapi/pull/143) ([mrvinti](https://github.com/mrvinti)) +- add switchport allowed vlan range capability [\#141](https://github.com/arista-eosplus/rbeapi/pull/141) ([rknaus](https://github.com/rknaus)) +- fix speed functions and add lacp port-priority functions [\#139](https://github.com/arista-eosplus/rbeapi/pull/139) ([rknaus](https://github.com/rknaus)) +- Fix rpm uninstall issue \#118 [\#134](https://github.com/arista-eosplus/rbeapi/pull/134) ([jerearista](https://github.com/jerearista)) +- Switchconfig rpms for chef [\#130](https://github.com/arista-eosplus/rbeapi/pull/130) ([jerearista](https://github.com/jerearista)) +- Switchconfig zap empty lines [\#128](https://github.com/arista-eosplus/rbeapi/pull/128) ([jerearista](https://github.com/jerearista)) +- Validate array param options [\#126](https://github.com/arista-eosplus/rbeapi/pull/126) ([websitescenes](https://github.com/websitescenes)) +- Wip load interval v2 [\#122](https://github.com/arista-eosplus/rbeapi/pull/122) ([n1cn0c](https://github.com/n1cn0c)) +- Created vlans set\_trunk\_groups method. [\#119](https://github.com/arista-eosplus/rbeapi/pull/119) ([devrobo](https://github.com/devrobo)) + +## [v0.5.1](https://github.com/arista-eosplus/rbeapi/tree/v0.5.1) (2016-02-16) +[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.5.0...v0.5.1) + +**Implemented enhancements:** + +- get\_connect should raise an error instead of returning nil if no connection is found [\#31](https://github.com/arista-eosplus/rbeapi/issues/31) +- Add build badges to the README.md [\#108](https://github.com/arista-eosplus/rbeapi/pull/108) ([jerearista](https://github.com/jerearista)) + +**Fixed bugs:** + +- PeerEthernet regex issue [\#109](https://github.com/arista-eosplus/rbeapi/issues/109) + +**Closed issues:** + +- Add support for commands with input [\#100](https://github.com/arista-eosplus/rbeapi/issues/100) +- Wildcard connection config gets clobbered [\#86](https://github.com/arista-eosplus/rbeapi/issues/86) + +**Merged pull requests:** + +- Release 0.5.1 to master [\#117](https://github.com/arista-eosplus/rbeapi/pull/117) ([jerearista](https://github.com/jerearista)) +- Release 0.5.1 [\#116](https://github.com/arista-eosplus/rbeapi/pull/116) ([jerearista](https://github.com/jerearista)) +- Release 0.5.1 [\#115](https://github.com/arista-eosplus/rbeapi/pull/115) ([jerearista](https://github.com/jerearista)) +- Only first trunk group was being returned. [\#114](https://github.com/arista-eosplus/rbeapi/pull/114) ([devrobo](https://github.com/devrobo)) +- Add support for DEFAULT section to eapi config file. [\#111](https://github.com/arista-eosplus/rbeapi/pull/111) ([devrobo](https://github.com/devrobo)) +- Remove getter for timeouts and use attr\_reader instead. [\#107](https://github.com/arista-eosplus/rbeapi/pull/107) ([websitescenes](https://github.com/websitescenes)) +- Added doc for trunk groups to get. [\#106](https://github.com/arista-eosplus/rbeapi/pull/106) ([devrobo](https://github.com/devrobo)) +- Tightening up documentation. [\#105](https://github.com/arista-eosplus/rbeapi/pull/105) ([websitescenes](https://github.com/websitescenes)) +- Added support for setting system banners. [\#104](https://github.com/arista-eosplus/rbeapi/pull/104) ([devrobo](https://github.com/devrobo)) + +## [v0.5.0](https://github.com/arista-eosplus/rbeapi/tree/v0.5.0) (2016-01-12) +[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.4.0...v0.5.0) + +**Implemented enhancements:** + +- Improve VARP and VARP interface parsing [\#79](https://github.com/arista-eosplus/rbeapi/issues/79) +- Need system tests for all api modules [\#66](https://github.com/arista-eosplus/rbeapi/issues/66) +- rbeapi coding documentation incomplete [\#62](https://github.com/arista-eosplus/rbeapi/issues/62) +- switchport api should support trunk groups [\#38](https://github.com/arista-eosplus/rbeapi/issues/38) +- Need units tests for framework [\#30](https://github.com/arista-eosplus/rbeapi/issues/30) +- Need unit test to verify read and open timeout in eapi conf file override default [\#29](https://github.com/arista-eosplus/rbeapi/issues/29) +- Unit tests for switchports [\#94](https://github.com/arista-eosplus/rbeapi/pull/94) ([websitescenes](https://github.com/websitescenes)) +- Ensure all parse methods are private. [\#93](https://github.com/arista-eosplus/rbeapi/pull/93) ([websitescenes](https://github.com/websitescenes)) +- test timeout values [\#92](https://github.com/arista-eosplus/rbeapi/pull/92) ([websitescenes](https://github.com/websitescenes)) +- Relax check on getall entries [\#91](https://github.com/arista-eosplus/rbeapi/pull/91) ([devrobo](https://github.com/devrobo)) +- Update framework tests [\#90](https://github.com/arista-eosplus/rbeapi/pull/90) ([websitescenes](https://github.com/websitescenes)) +- Add lacp\_mode option when setting port-channel members. [\#89](https://github.com/arista-eosplus/rbeapi/pull/89) ([devrobo](https://github.com/devrobo)) +- Added support for trunk groups. [\#88](https://github.com/arista-eosplus/rbeapi/pull/88) ([devrobo](https://github.com/devrobo)) +- Add basic framework tests. [\#85](https://github.com/arista-eosplus/rbeapi/pull/85) ([websitescenes](https://github.com/websitescenes)) +- Address code coverage gaps [\#84](https://github.com/arista-eosplus/rbeapi/pull/84) ([websitescenes](https://github.com/websitescenes)) + +**Fixed bugs:** + +- failure when eapi.conf is not formatted correctly [\#82](https://github.com/arista-eosplus/rbeapi/issues/82) +- Enable password setting in the .eapi.conf file not honored [\#72](https://github.com/arista-eosplus/rbeapi/issues/72) +- API interfaces should accept an lacp\_mode to configure for port-channel members [\#58](https://github.com/arista-eosplus/rbeapi/issues/58) +- Copy configuration entry before modifying with connection specific info. [\#101](https://github.com/arista-eosplus/rbeapi/pull/101) ([devrobo](https://github.com/devrobo)) +- Add terminal to configure command to work around AAA issue found in p… [\#99](https://github.com/arista-eosplus/rbeapi/pull/99) ([devrobo](https://github.com/devrobo)) +- Set enable password for a connection. [\#96](https://github.com/arista-eosplus/rbeapi/pull/96) ([devrobo](https://github.com/devrobo)) +- Catch errors and syslog them when parsing eapi conf file. [\#95](https://github.com/arista-eosplus/rbeapi/pull/95) ([devrobo](https://github.com/devrobo)) +- Ensure that nil is returned when you try to get nonexistent username. [\#83](https://github.com/arista-eosplus/rbeapi/pull/83) ([websitescenes](https://github.com/websitescenes)) + +**Merged pull requests:** + +- Update documentation [\#97](https://github.com/arista-eosplus/rbeapi/pull/97) ([websitescenes](https://github.com/websitescenes)) + +## [v0.4.0](https://github.com/arista-eosplus/rbeapi/tree/v0.4.0) (2015-11-21) +[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.3.0...v0.4.0) + +**Implemented enhancements:** + +- Add users API [\#78](https://github.com/arista-eosplus/rbeapi/issues/78) +- Support BGP maximum paths [\#77](https://github.com/arista-eosplus/rbeapi/issues/77) +- Feature puppet4 swix [\#74](https://github.com/arista-eosplus/rbeapi/pull/74) ([jerearista](https://github.com/jerearista)) +- Add argument checking for the track hash. [\#70](https://github.com/arista-eosplus/rbeapi/pull/70) ([devrobo](https://github.com/devrobo)) +- Fix spec test issue from pull request \#61 [\#69](https://github.com/arista-eosplus/rbeapi/pull/69) ([devrobo](https://github.com/devrobo)) +- Update RPM packaging to accomodate Puppet 4 AIO agent [\#68](https://github.com/arista-eosplus/rbeapi/pull/68) ([jerearista](https://github.com/jerearista)) +- Update RPM packaging names, requirements, and paths due to Puppet 4 [\#65](https://github.com/arista-eosplus/rbeapi/pull/65) ([jerearista](https://github.com/jerearista)) +- Add support for getting and setting maximum paths. [\#52](https://github.com/arista-eosplus/rbeapi/pull/52) ([devrobo](https://github.com/devrobo)) + +**Fixed bugs:** + +- api interfaces get\_members\(\) passes format: instead of encoding: to enable\(\) [\#59](https://github.com/arista-eosplus/rbeapi/issues/59) +- bgp API should return nil instead of an empty hash [\#50](https://github.com/arista-eosplus/rbeapi/issues/50) +- Changed bgp.rb get routine to return nil if the config could not be o… [\#67](https://github.com/arista-eosplus/rbeapi/pull/67) ([devrobo](https://github.com/devrobo)) +- Correct option to request 'text' results [\#61](https://github.com/arista-eosplus/rbeapi/pull/61) ([jerearista](https://github.com/jerearista)) + +**Merged pull requests:** + +- Merge develop to master for Release 0.4.0 [\#81](https://github.com/arista-eosplus/rbeapi/pull/81) ([jerearista](https://github.com/jerearista)) +- Release 0.4.0 [\#80](https://github.com/arista-eosplus/rbeapi/pull/80) ([jerearista](https://github.com/jerearista)) +- Update rubocop version and rectify related test failures. [\#76](https://github.com/arista-eosplus/rbeapi/pull/76) ([websitescenes](https://github.com/websitescenes)) +- Add method to enable ip routing to the system API [\#75](https://github.com/arista-eosplus/rbeapi/pull/75) ([websitescenes](https://github.com/websitescenes)) +- Added vrrp api module and unit tests. [\#64](https://github.com/arista-eosplus/rbeapi/pull/64) ([devrobo](https://github.com/devrobo)) +- Adding feature routemap [\#63](https://github.com/arista-eosplus/rbeapi/pull/63) ([websitescenes](https://github.com/websitescenes)) +- varp and varp interfaces update. [\#60](https://github.com/arista-eosplus/rbeapi/pull/60) ([websitescenes](https://github.com/websitescenes)) +- Fixed comment for value param for set\_lacp\_timeout method. [\#57](https://github.com/arista-eosplus/rbeapi/pull/57) ([devrobo](https://github.com/devrobo)) +- Feature user updates [\#56](https://github.com/arista-eosplus/rbeapi/pull/56) ([websitescenes](https://github.com/websitescenes)) +- Update max\_paths to maximum\_paths and max\_ecmp\_paths to maximum\_ecmp\_… [\#55](https://github.com/arista-eosplus/rbeapi/pull/55) ([websitescenes](https://github.com/websitescenes)) +- Fixed issues on the new bgp create call. [\#54](https://github.com/arista-eosplus/rbeapi/pull/54) ([devrobo](https://github.com/devrobo)) +- Added support for getting users information. [\#53](https://github.com/arista-eosplus/rbeapi/pull/53) ([devrobo](https://github.com/devrobo)) +- add dry-run mode [\#42](https://github.com/arista-eosplus/rbeapi/pull/42) ([kakkotetsu](https://github.com/kakkotetsu)) + +## [v0.3.0](https://github.com/arista-eosplus/rbeapi/tree/v0.3.0) (2015-08-24) +[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.2.0...v0.3.0) + +**Fixed bugs:** + +- rbeapi exits if $HOME is not set [\#46](https://github.com/arista-eosplus/rbeapi/issues/46) + +**Merged pull requests:** + +- Release 0.3.0 to master [\#51](https://github.com/arista-eosplus/rbeapi/pull/51) ([jerearista](https://github.com/jerearista)) +- Release 0.3.0 [\#49](https://github.com/arista-eosplus/rbeapi/pull/49) ([jerearista](https://github.com/jerearista)) +- Only search home directory if HOME is defined ISSUE \#46 [\#48](https://github.com/arista-eosplus/rbeapi/pull/48) ([devrobo](https://github.com/devrobo)) +- set\_shutdown needs to negate the enable option. [\#47](https://github.com/arista-eosplus/rbeapi/pull/47) ([devrobo](https://github.com/devrobo)) +- Feature staticroutes [\#45](https://github.com/arista-eosplus/rbeapi/pull/45) ([jerearista](https://github.com/jerearista)) +- Broaden the regex matching for portchannel member interfaces [\#44](https://github.com/arista-eosplus/rbeapi/pull/44) ([jerearista](https://github.com/jerearista)) +- Update rpm requires sections for rbeapi [\#43](https://github.com/arista-eosplus/rbeapi/pull/43) ([jerearista](https://github.com/jerearista)) +- Added support for BGP along with unit tests. [\#41](https://github.com/arista-eosplus/rbeapi/pull/41) ([devrobo](https://github.com/devrobo)) +- Eliminate overloading value option in command\_builder. [\#39](https://github.com/arista-eosplus/rbeapi/pull/39) ([devrobo](https://github.com/devrobo)) + +## [v0.2.0](https://github.com/arista-eosplus/rbeapi/tree/v0.2.0) (2015-07-08) +[Full Changelog](https://github.com/arista-eosplus/rbeapi/compare/v0.1.0...v0.2.0) + +**Implemented enhancements:** + +- Add \[connection:\*\] to eapi.conf syntax [\#18](https://github.com/arista-eosplus/rbeapi/issues/18) +- can't rake all\_rpms [\#11](https://github.com/arista-eosplus/rbeapi/issues/11) +- add read\_timeout and open\_timeout to client.rb [\#10](https://github.com/arista-eosplus/rbeapi/issues/10) +- Add netaddr rubygem rpm [\#35](https://github.com/arista-eosplus/rbeapi/pull/35) ([jerearista](https://github.com/jerearista)) +- Fix RPM packaging for Ubuntu systems. Fixes \#11 [\#14](https://github.com/arista-eosplus/rbeapi/pull/14) ([jerearista](https://github.com/jerearista)) + +**Fixed bugs:** + +- rbeapi swix/rpms fail to install completely on EOS [\#34](https://github.com/arista-eosplus/rbeapi/issues/34) +- interfaces API may appear to return duplicate port-channel members on MLAG interfaces [\#16](https://github.com/arista-eosplus/rbeapi/issues/16) +- connection profile name is not copied to host attribute [\#6](https://github.com/arista-eosplus/rbeapi/issues/6) +- NoMethodError when accessing a vlan-name containing a '-' character [\#5](https://github.com/arista-eosplus/rbeapi/issues/5) + +**Merged pull requests:** + +- Release 0.2.0 to master [\#37](https://github.com/arista-eosplus/rbeapi/pull/37) ([jerearista](https://github.com/jerearista)) +- Release 0.2.0 version and doc updates [\#36](https://github.com/arista-eosplus/rbeapi/pull/36) ([jerearista](https://github.com/jerearista)) +- Change class name and hash key names. [\#33](https://github.com/arista-eosplus/rbeapi/pull/33) ([devrobo](https://github.com/devrobo)) +- name path through if default connection is used [\#32](https://github.com/arista-eosplus/rbeapi/pull/32) ([kakkotetsu](https://github.com/kakkotetsu)) +- Added API for standard ACLs with unit and system test. [\#28](https://github.com/arista-eosplus/rbeapi/pull/28) ([devrobo](https://github.com/devrobo)) +- Add \[connection:\*\] to eapi.conf syntax Issue \#18 [\#27](https://github.com/arista-eosplus/rbeapi/pull/27) ([devrobo](https://github.com/devrobo)) +- Add read\_timeout and open\_timeout to client.rb Issue 10 [\#26](https://github.com/arista-eosplus/rbeapi/pull/26) ([devrobo](https://github.com/devrobo)) +- Set host key to connection profile name if host key not set. ISSUE 6 [\#25](https://github.com/arista-eosplus/rbeapi/pull/25) ([devrobo](https://github.com/devrobo)) +- Changed default transport to https to match README.md [\#24](https://github.com/arista-eosplus/rbeapi/pull/24) ([devrobo](https://github.com/devrobo)) +- Fixes to the rbeabi library [\#23](https://github.com/arista-eosplus/rbeapi/pull/23) ([devrobo](https://github.com/devrobo)) +- Cleanup spec tests, all tests are passing. [\#21](https://github.com/arista-eosplus/rbeapi/pull/21) ([devrobo](https://github.com/devrobo)) +- Doc fixes [\#20](https://github.com/arista-eosplus/rbeapi/pull/20) ([devrobo](https://github.com/devrobo)) +- Addressed RuboCop reported issues. [\#19](https://github.com/arista-eosplus/rbeapi/pull/19) ([devrobo](https://github.com/devrobo)) +- Fixes \#16 - Change port-channel members regex to anchor on word-boundary. [\#17](https://github.com/arista-eosplus/rbeapi/pull/17) ([jerearista](https://github.com/jerearista)) +- Rubocop driven cleanup. Spec tests still need to be fixed. [\#12](https://github.com/arista-eosplus/rbeapi/pull/12) ([devrobo](https://github.com/devrobo)) +- add HTTP read\_timeout [\#9](https://github.com/arista-eosplus/rbeapi/pull/9) ([kakkotetsu](https://github.com/kakkotetsu)) +- Add support for spanning tree portfast\_type. [\#8](https://github.com/arista-eosplus/rbeapi/pull/8) ([devrobo](https://github.com/devrobo)) +- Fix typo in set\_flowcontrol method. [\#7](https://github.com/arista-eosplus/rbeapi/pull/7) ([devrobo](https://github.com/devrobo)) +- Feature - generate RPMs and instructions for SWIX files [\#4](https://github.com/arista-eosplus/rbeapi/pull/4) ([jerearista](https://github.com/jerearista)) +- Fix a couple typos, minor formatting in README.md [\#3](https://github.com/arista-eosplus/rbeapi/pull/3) ([brandt](https://github.com/brandt)) +- Fix missing OpenSSL require [\#2](https://github.com/arista-eosplus/rbeapi/pull/2) ([brandt](https://github.com/brandt)) + +## [v0.1.0](https://github.com/arista-eosplus/rbeapi/tree/v0.1.0) (2015-02-25) + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file From 6f192a0af48888d2c4cb65cfeaf38d205a253118 Mon Sep 17 00:00:00 2001 From: Jere Julian Date: Fri, 23 Sep 2016 06:23:43 -0400 Subject: [PATCH 60/60] Revert "Add github_changelog_generator for releases" This causes issues when testing on older Ruby such as 1.9.3. This reverts commit f2e5949ce9d38ca2ddd71ce4c0e0c2b84007b893. --- Gemfile | 4 ---- Rakefile | 7 +------ 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index b0a3e5b..1ccdebf 100644 --- a/Gemfile +++ b/Gemfile @@ -26,7 +26,6 @@ group :development, :test do gem 'ci_reporter_rspec', require: false gem 'simplecov-json', require: false gem 'simplecov-rcov', require: false - gem 'github_changelog_generator', require: false end # Rubocop > 0.37 requires a gem that only works with ruby 2.x @@ -41,8 +40,5 @@ else gem 'rubocop', '>=0.35.1' end end -if RUBY_VERSION.to_f < 2.2 - gem 'rack', '<2.0' -end # vim:ft=ruby diff --git a/Rakefile b/Rakefile index a0423e3..7b4cb2e 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,4 @@ require 'bundler/gem_tasks' -require 'github_changelog_generator/task' $LOAD_PATH.unshift File.expand_path('../lib', __FILE__) require 'rbeapi/version' @@ -148,11 +147,7 @@ task swix: :all_rpms do puts "#\n################################################\n\n" end -GitHubChangelogGenerator::RakeTask.new :changelog do |config| - config.future_release = Rbeapi::VERSION -end - -task release: [:changelog, :build] do +task release: :build do system "gem push rbeapi-#{Rbeapi::VERSION}.gem" end