From fbc1bd806325c83935accd9dc9329489f962871b Mon Sep 17 00:00:00 2001 From: Priyal Jain Date: Fri, 26 Jun 2015 15:21:23 +0530 Subject: [PATCH 01/33] Update bridge_domain.rb --- lib/junos-ez/l2_ports/bridge_domain.rb | 632 +++++++++++++++++++++++++ 1 file changed, 632 insertions(+) diff --git a/lib/junos-ez/l2_ports/bridge_domain.rb b/lib/junos-ez/l2_ports/bridge_domain.rb index e69de29..05a2e01 100644 --- a/lib/junos-ez/l2_ports/bridge_domain.rb +++ b/lib/junos-ez/l2_ports/bridge_domain.rb @@ -0,0 +1,632 @@ +class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN< Junos::Ez::L2ports::Provider + + ### --------------------------------------------------------------- + ### XML top placement + ### --------------------------------------------------------------- + + def xml_at_top + Nokogiri::XML::Builder.new {|xml| xml.configuration { + xml.interfaces { + print "\n **** inside xml_at_top********\n" + print "@name:", @name + return xml_at_element_top( xml, @name ) + } + }} + end + + # set the edit anchor inside the ethernet-switching stanza + # we will need to 'up-out' when making changes to the + # unit information, like description + + def xml_at_element_top( xml, name ) + print "\n************ inside xml_at_element_top ****************\n" + print "xml and name:" + print xml.to_xml + print name + xml.interface { + xml.name name + xml.send(:'native-vlan-id') + xml.unit { + xml.name '0' + print "-----xml: ", xml.to_xml + return xml + } + } + end + + ### --------------------------------------------------------------- + ### XML property readers + ### --------------------------------------------------------------- + + def xml_get_has_xml( xml ) + print "\n ************** inside xml_get_has_xml **************\n\n xml is:" + print xml.to_xml + # second unit contains the family/ethernet-switching stanza + got = xml.xpath('//unit')[0] + + # if this resource doesn't exist we need to default some + # values into has/should variables + print "\n got----: ",got + unless got + @has[:vlan_tagging] = false + @should = @has.clone + end + got + end + + def xml_read_parser( as_xml, as_hash ) + print "\n\n ************** inside xml_read_parser *************** \n\n" + print "as_xml: " + print as_xml + print "as_hash: ",as_hash + ## reading is anchored at the [... unit 0 ...] level + set_has_status( as_xml, as_hash ) + + xml_when_item(as_xml.xpath('description')){|i| as_hash[:description] = i.text} + + f_eth = as_xml.xpath('family/bridge') + as_hash[:vlan_tagging] = f_eth.xpath('interface-mode').text.chomp == 'trunk' + + # obtain a copy of the running state, this is needed in case the config + # is located under the [edit vlans] stanza vs. [edit interfaces] + + ifs_name = @name || as_xml.xpath('ancestor::interface/name').text.strip + eth_port_vlans = _get_eth_port_vlans_h( ifs_name ) + @under_vlans = [] + + # --- access port + + if as_hash[:vlan_tagging] == false + print "\n\n &&&&&&&&&&& vlan tagging flase &&&&&&&&&&&&&& \n\n" + xml_when_item(f_eth.xpath('domain/vlan-id')){ |i| as_hash[:untagged_vlan] = i.text.chomp } + unless as_hash[:untagged_vlan] + as_hash[:untagged_vlan] = eth_port_vlans[:untagged] + @under_vlans << eth_port_vlans[:untagged] + end + return + end + + # --- trunk port + + as_hash[:untagged_vlan] ||= eth_port_vlans[:untagged] + as_hash[:tagged_vlans] = f_eth.xpath('domain/vlan-id-list').collect { |v| v.text.chomp }.to_set + (eth_port_vlans[:tagged] - as_hash[:tagged_vlans]).each do |vlan| + as_hash[:tagged_vlans] << vlan + @under_vlans << vlan + end + + # native-vlan-id is set at the interface level, and is the VLAN-ID, not the vlan + # name. So we need to do a bit of translating here. The *ASSUMPTION* is that the + # native-vlan-id value is a given VLAN in the tagged_vlan list. So we will use + # that list to do the reverse lookup on the tag-id => name + + xml_when_item(f_eth.xpath('ancestor::interface/native-vlan-id')){ |i| + as_hash[:untagged_vlan] = _vlan_tag_id_to_name( i.text.chomp, as_hash ) + } + end + + ### --------------------------------------------------------------- + ### XML on_create, on_delete handlers + ### --------------------------------------------------------------- + + ## overload the xml_on_delete method since we may need + ## to do some cleanup work in the [edit vlans] stanza + + def xml_on_delete( xml ) + print "\n************ inside xml_on_delete **************\n xml:" + print xml + @ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface') + print " &&&&&&&&&&&& 1 &&&&&&&&&&&&" + @ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config + print " &&&&&&&&&&&& 2 &&&&&&&&&&&&" + if @ifd.xpath('//native-vlan-id') + print "vlan -id exists" + end + ## need to add check if any native-vlan-id is present or not (untagged vlan)##### + #if is_trunk? and @ifd.xpath('//native-vlan-id') + # _delete_native_vlan_id( xml ) + #end + + return unless @under_vlans + print " &&&&&&&&&&&& 3 &&&&&&&&&&&&" + print @under_vlans + return if @under_vlans.empty? + print " &&&&&&&&&&&& 4 &&&&&&&&&&&&" + + _xml_rm_under_vlans( xml, @under_vlans ) + print "\n ^^^^^^^^^^^ exiting xml_on_delete ^^^^^^^^^^^\n" + end + + ### --------------------------------------------------------------- + ### XML property writers + ### --------------------------------------------------------------- + + def xml_at_here( xml ) + print "\n ************** inside xml_at_here *************\n" + print xml.to_xml + @ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface') + @ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config + print "@ifd:" + print @ifd + xml.family { + xml.send(:'bridge') { + print "xml after removing ifd is: ",xml + return xml + } + } + end + + def xml_build_change( nop = nil ) + @under_vlans ||= [] # handles case for create'd port + + if mode_changed? + @should[:untagged_vlan] ||= @has[:untagged_vlan] + end + + super xml_at_here( xml_at_top ) + end + + ## ---------------------------------------------------------------- + ## :description + ## ---------------------------------------------------------------- + + ## overload default method since we need to "up-out" of the + ## ethernet-switching stanza + + def xml_change_description( xml ) + unit = xml.parent.xpath('ancestor::unit')[0] + Nokogiri::XML::Builder.with( unit ){ |x| + xml_set_or_delete( x, 'description', @should[:description] ) + } + end + + ## ---------------------------------------------------------------- + ## :vlan_tagging + ## ---------------------------------------------------------------- + + def xml_change_vlan_tagging( xml ) + print "\n\n ******************* xml_change_vlan_tagging *******************\n\n xml" + print xml.to_xml + port_mode = should_trunk? ? 'trunk' : 'access' + xml.send(:'interface-mode', port_mode ) + + # when the vlan_tagging value changes then this method + # will trigger updates to the untagged_vlan and tagged_vlans + # resource values as well. + # !!! DO NOT SWAP THIS ORDER untagged processing *MUST* BE FIRST! + + upd_untagged_vlan( xml ) + upd_tagged_vlans( xml ) + + return true + end + + ## ---------------------------------------------------------------- + ## :tagged_vlans + ## ---------------------------------------------------------------- + + def xml_change_tagged_vlans( xml ) + print "\n ************** inside xml_change_tagged_vlans *************\n\nxml:" + print xml.to_xml + return false if mode_changed? + upd_tagged_vlans( xml ) + end + + def upd_tagged_vlans( xml ) + print "\n ************** inside upd_tagged_vlans *************\n\n xml:" + print xml + return false unless should_trunk? + + print @should[:tagged_vlans] + print @has[:tagged_vlans] + + @should[:tagged_vlans] = @should[:tagged_vlans].to_set if @should[:tagged_vlans].kind_of? Array + @has[:tagged_vlans] = @has[:tagged_vlans].to_set if @has[:tagged_vlans].kind_of? Array + + v_should = @should[:tagged_vlans] || Set.new + v_has = @has[:tagged_vlans] || Set.new + + print "hiiiiii" + print v_should + print v_has + del = v_has - v_should + add = v_should - v_has + + print "add and del is: ", add, del + + add.each do |n| + # Display the element. + puts "add value is:", n + end + + del_under_vlans = del & @under_vlans + print "hello=========" + unless del_under_vlans.empty? + del = del ^ @under_vlans + _xml_rm_under_vlans( xml, del_under_vlans ) + @under_vlans = [] + end + puts "adds size is",add.size() + + + if add or del + print "\n inside add or del \n" + #xml.send(:'vlan-id') { + # del.each { |v| xml.members v, Netconf::JunosConfig::DELETE } + # add.each { |v| xml.members v } + add.each {|v| print "\n %%%%%%%%%%%%%%%%%% _vlan_name_to_tag_id( v ) \n", _vlan_name_to_tag_id( v )} + del.each{|v| xml.send(:'vlan-id-list', _vlan_name_to_tag_id( v ), Netconf::JunosConfig::DELETE)} + add.each{|v| xml.send( :'vlan-id-list', _vlan_name_to_tag_id(v) )} + print "\n %%%%%%% xml: \n", xml.to_xml + end + print "\n\n *************** exiting **************** \n\n" + return true + end + + ## ---------------------------------------------------------------- + ## :untagged_vlan + ## ---------------------------------------------------------------- + + def xml_change_untagged_vlan( xml ) + print "\n ************** inside xml_change_untagged_vlan *************\n\n xml:----" + print xml.to_xml + return false if mode_changed? + upd_untagged_vlan( xml ) + end + + def upd_untagged_vlan( xml ) + print "\n ************** inside upd_untagged_vlan *************\n\n xml:" + print xml.to_xml + self.class.change_untagged_vlan( self, xml ) + end + +end + +##### --------------------------------------------------------------- +##### Class methods for handling state-transitions between +##### configurations (tagged/untagged) +##### --------------------------------------------------------------- + +class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN + + # creating some class definitions ... + # this is a bit complicated because we need to handle port-mode + # change transitions; basically dealing with the fact that + # trunk ports use 'native-vlan-id' and access ports have a + # vlan member definition; i.e. they don't use native-vlan-id, ugh. + # Rather than doing all this logic as if/then/else statements, + # I've opted to using a proc jump-table technique. Lessons + # learned from lots of embedded systems programming :-) + + def self.init_jump_table + + # auto-hash table, majik! + hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)})) + + # ------------------------------------------------------------------ + # - jump table for handling various untagged vlan change use-cases + # ------------------------------------------------------------------ + # There are three criteria for selection: + # | is_trunk | will_trunk | no_untg | + # ------------------------------------------------------------------ + + # - will not have untagged vlan + hash[false][false][true] = self.method(:ac_ac_nountg) + hash[false][true][true] = self.method(:ac_tr_nountg) + hash[true][false][true] = self.method(:tr_ac_nountg) + hash[true][true][true] = self.method(:tr_tr_nountg) + + # - will have untagged vlan + hash[false][false][false] = self.method(:ac_ac_untg) + hash[false][true][false] = self.method(:ac_tr_untg) + hash[true][false][false] = self.method(:tr_ac_untg) + hash[true][true][false] = self.method(:tr_tr_untg) + + hash + end + + ### invoke the correct method from the jump table + ### based on the three criteria to select the action + + def self.change_untagged_vlan( this, xml ) + print "\n\n ********** inside change_untagged_vlan *************\n\n" + @@ez_l2_jmptbl ||= init_jump_table + print "\n @@ez_l2_jmptbl: ",@@ez_l2_jmptbl + proc = @@ez_l2_jmptbl[this.is_trunk?][this.should_trunk?][this.should[:untagged_vlan].nil?] + print "\n proc:",proc + proc.call( this, xml ) + end + + ### ------------------------------------------------------------- + ### The following are all the change transition functions for + ### each of the use-cases + ### ------------------------------------------------------------- + + def self.ac_ac_nountg( this, xml ) + print "\n !!!!!!!!!!! inside ac_ac_nountg !!!!!!!!!!!!!!!\n\n\n" + #^^^^^^^ create log + #NetdevJunos::Log.debug "ac_ac_nountg" + # @@@ a port *MUST* be assigned to a vlan in access mode on MX. + # @@@ generate an error! + raise Junos::Ez::NoProviderError, "a port *MUST* be assigned to a vlan in access mode on MX." + #raise "ERROR!!! a port *MUST* be assigned to a vlan in access mode on MX." + end + + ########## need to see################# + def self.ac_tr_nountg( this, xml ) + print "\n ******** inside ac_tr_nountg ********\n" + #unless (untg_vlan = this.has[:untagged_vlan]).nil? + # this._xml_rm_ac_untagged_vlan( xml ) + #end + #no action needed handled already + print "xml is:", xml.to_xml + end + ######################################### + + def self.tr_ac_nountg( this, xml ) + print "\n ******** inside tr_ac_nountg ********\n" + #this._delete_native_vlan_id( xml ) + #this._xml_rm_these_vlans( xml, this.has[:tagged_vlans ] ) if this.has[:tagged_vlans] + print "port must be assigned to vlan in access mode on MX" + raise Junos::Ez::NoProviderError, "port must be assigned to vlan in access mode on MX" + #raise "ERROR!! untagged_vlan missing, port must be assigned to a VLAN" + end + + def self.tr_tr_nountg( this, xml ) + print "\n ******** inside tr_tr_nountg ********\n" + this._delete_native_vlan_id( xml ) + print "xml is: ", xml.to_xml + end + + ## ---------------------------------------------------------------- + ## transition where port WILL-HAVE untagged-vlan + ## ---------------------------------------------------------------- + + ## setting untagged vlan id ######### + #######working######### + def self.ac_ac_untg( this, xml ) + print "\n ******** inside ac_ac_untg ********\n" + #this._xml_rm_ac_untagged_vlan( xml ) + print "\n xml is: ",xml.to_xml + print this.should[:untagged_vlan] + vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] ) + xml.send :'vlan-id', vlan_id + #xml.send :'vlan-id', (this._vlan_name_to_tag_id(this.should[:untagged_vlan])) + #xml.members this.should[:untagged_vlan] + #this._vlan_name_to_tag_id(this.should[:untagged_vlan]) + # print "hello: ",this._vlan_name_to_tag_id(this.should[:untagged_vlan]) + print "\n xml after vlan is: ",xml.to_xml + end + ###########working################# + + def self.ac_tr_untg( this, xml ) + print "\n inside ac_tr_untg \n" + # move untagged vlan to native-vlan-id ... + was_untg_vlan = this.has[:untagged_vlan] + this._set_native_vlan_id( xml, this.should[:untagged_vlan] ) + this._xml_rm_ac_untagged_vlan( xml ) if was_untg_vlan + end + + def self.tr_ac_untg( this, xml ) + print "\n ******** inside tr_ac_untg ********\n" + this._delete_native_vlan_id( xml ) + #this._xml_rm_these_vlans( xml, this.has[:tagged_vlans ] ) if this.has[:tagged_vlans] + #this._set_vlan_id(xml) + vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] ) + xml.send( :'vlan-id', vlan_id ) + print "xml: ", xml.to_xml + end + + def self.tr_tr_untg( this, xml ) + print "\n\n *********inside tr_tr_untg************\n\n" + print "xml: ", xml.to_xml + this._set_native_vlan_id(xml, this.should[:untagged_vlan]) + print "\n @@@@@@@@ xml is : ", xml + end + +end + +##### --------------------------------------------------------------- +##### Provider collection methods +##### --------------------------------------------------------------- + +class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN + + def build_list + print "\n\n ********** inside build_list ****************\n\n" + begin + got = @ndev.rpc.get_bridge_instance_information( :brief => true) + rescue => e + # in this case, no ethernet-switching is enabled so return empty list + return [] + end + got.xpath('//l2iff-interface-name').collect{ |ifn| ifn.text.split('.')[0] } + end + + def build_catalog + print "\n\n************ inside build_catalog *************\n\n" + @catalog = {} + return @catalog if list!.empty? + + list.each do |ifs_name| + @ndev.rpc.get_configuration{ |xml| + xml.interfaces { + xml_at_element_top( xml, ifs_name ) + } + }.xpath('interfaces/interface').each do |ifs_xml| + @catalog[ifs_name] = {} + unit = xml_get_has_xml( ifs_xml ) + xml_read_parser( unit, @catalog[ifs_name] ) + end + end + + @catalog + end + +end + +##### --------------------------------------------------------------- +##### !!!!! PRIVATE METHODS !!!! +##### --------------------------------------------------------------- + +class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN + private + + def _get_eth_port_vlans_h( ifs_name ) + print "\n********* inside _get_eth_port_vlans_h ****************\n" + got = @ndev.rpc.get_bridge_instance_information(:interface => ifs_name) + ret_h = {:untagged => nil, :tagged => Set.new } + got.xpath('//l2ng-l2ald-iff-interface-entry').each do |vlan| + # one of the node-set elements (the first one?) contains the interface name. + # this doesn't have any VLAN information, so skip it. + next if vlan.xpath('l2iff-interface-name') + + vlan_name = vlan.xpath('//l2rtb-bridge-vlan').text.strip + if vlan.xpath('//l2rtb-interface-vlan-member-tagness') + tgdy = vlan.xpath('//l2rtb-interface-vlan-member-tagness').text.strip + if tgdy == 'untagged' + ret_h[:untagged] = vlan_name + else + ret_h[:tagged] << vlan_name + end + else + ret_h[:tagged]< Date: Wed, 15 Jul 2015 16:15:28 +0530 Subject: [PATCH 02/33] adding support for l2_interface --- lib/junos-ez/l2_ports.rb | 8 +- lib/junos-ez/l2_ports/bridge_domain.rb | 1147 +++++++++++------------- 2 files changed, 519 insertions(+), 636 deletions(-) diff --git a/lib/junos-ez/l2_ports.rb b/lib/junos-ez/l2_ports.rb index 21f8fbe..c94ea66 100644 --- a/lib/junos-ez/l2_ports.rb +++ b/lib/junos-ez/l2_ports.rb @@ -18,7 +18,8 @@ def self.Provider( ndev, varsym ) when :VLAN_L2NG Junos::Ez::L2ports::Provider::VLAN_L2NG.new( ndev ) when :BRIDGE_DOMAIN - raise ArgumentError, "under development" + Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN.new(ndev) + #raise ArgumentError, "under development" # Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN.new( ndev ) end @@ -49,7 +50,7 @@ def mode_changed? ### --------------------------------------------------------------- def xml_change__active( xml ) - par = xml.instance_variable_get(:@parent).at_xpath('ancestor::unit') + par = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface') value = @should[:_active] ? 'active' : 'inactive' par[value] = value # attribute name is same as value end @@ -60,7 +61,6 @@ def xml_change__active( xml ) require 'junos-ez/l2_ports/vlan' require 'junos-ez/l2_ports/vlan_l2ng' - -# require 'junos-ez/l2ports/bridge_domain' ... under development +require 'junos-ez/l2_ports/bridge_domain' diff --git a/lib/junos-ez/l2_ports/bridge_domain.rb b/lib/junos-ez/l2_ports/bridge_domain.rb index 05a2e01..ce23e7e 100644 --- a/lib/junos-ez/l2_ports/bridge_domain.rb +++ b/lib/junos-ez/l2_ports/bridge_domain.rb @@ -1,632 +1,515 @@ -class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN< Junos::Ez::L2ports::Provider - - ### --------------------------------------------------------------- - ### XML top placement - ### --------------------------------------------------------------- - - def xml_at_top - Nokogiri::XML::Builder.new {|xml| xml.configuration { - xml.interfaces { - print "\n **** inside xml_at_top********\n" - print "@name:", @name - return xml_at_element_top( xml, @name ) - } - }} - end - - # set the edit anchor inside the ethernet-switching stanza - # we will need to 'up-out' when making changes to the - # unit information, like description - - def xml_at_element_top( xml, name ) - print "\n************ inside xml_at_element_top ****************\n" - print "xml and name:" - print xml.to_xml - print name - xml.interface { - xml.name name - xml.send(:'native-vlan-id') - xml.unit { - xml.name '0' - print "-----xml: ", xml.to_xml - return xml - } - } - end - - ### --------------------------------------------------------------- - ### XML property readers - ### --------------------------------------------------------------- - - def xml_get_has_xml( xml ) - print "\n ************** inside xml_get_has_xml **************\n\n xml is:" - print xml.to_xml - # second unit contains the family/ethernet-switching stanza - got = xml.xpath('//unit')[0] - - # if this resource doesn't exist we need to default some - # values into has/should variables - print "\n got----: ",got - unless got - @has[:vlan_tagging] = false - @should = @has.clone - end - got - end - - def xml_read_parser( as_xml, as_hash ) - print "\n\n ************** inside xml_read_parser *************** \n\n" - print "as_xml: " - print as_xml - print "as_hash: ",as_hash - ## reading is anchored at the [... unit 0 ...] level - set_has_status( as_xml, as_hash ) - - xml_when_item(as_xml.xpath('description')){|i| as_hash[:description] = i.text} - - f_eth = as_xml.xpath('family/bridge') - as_hash[:vlan_tagging] = f_eth.xpath('interface-mode').text.chomp == 'trunk' - - # obtain a copy of the running state, this is needed in case the config - # is located under the [edit vlans] stanza vs. [edit interfaces] - - ifs_name = @name || as_xml.xpath('ancestor::interface/name').text.strip - eth_port_vlans = _get_eth_port_vlans_h( ifs_name ) - @under_vlans = [] - - # --- access port - - if as_hash[:vlan_tagging] == false - print "\n\n &&&&&&&&&&& vlan tagging flase &&&&&&&&&&&&&& \n\n" - xml_when_item(f_eth.xpath('domain/vlan-id')){ |i| as_hash[:untagged_vlan] = i.text.chomp } - unless as_hash[:untagged_vlan] - as_hash[:untagged_vlan] = eth_port_vlans[:untagged] - @under_vlans << eth_port_vlans[:untagged] - end - return - end - - # --- trunk port - - as_hash[:untagged_vlan] ||= eth_port_vlans[:untagged] - as_hash[:tagged_vlans] = f_eth.xpath('domain/vlan-id-list').collect { |v| v.text.chomp }.to_set - (eth_port_vlans[:tagged] - as_hash[:tagged_vlans]).each do |vlan| - as_hash[:tagged_vlans] << vlan - @under_vlans << vlan - end - - # native-vlan-id is set at the interface level, and is the VLAN-ID, not the vlan - # name. So we need to do a bit of translating here. The *ASSUMPTION* is that the - # native-vlan-id value is a given VLAN in the tagged_vlan list. So we will use - # that list to do the reverse lookup on the tag-id => name - - xml_when_item(f_eth.xpath('ancestor::interface/native-vlan-id')){ |i| - as_hash[:untagged_vlan] = _vlan_tag_id_to_name( i.text.chomp, as_hash ) - } - end - - ### --------------------------------------------------------------- - ### XML on_create, on_delete handlers - ### --------------------------------------------------------------- - - ## overload the xml_on_delete method since we may need - ## to do some cleanup work in the [edit vlans] stanza - - def xml_on_delete( xml ) - print "\n************ inside xml_on_delete **************\n xml:" - print xml - @ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface') - print " &&&&&&&&&&&& 1 &&&&&&&&&&&&" - @ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config - print " &&&&&&&&&&&& 2 &&&&&&&&&&&&" - if @ifd.xpath('//native-vlan-id') - print "vlan -id exists" - end - ## need to add check if any native-vlan-id is present or not (untagged vlan)##### - #if is_trunk? and @ifd.xpath('//native-vlan-id') - # _delete_native_vlan_id( xml ) - #end - - return unless @under_vlans - print " &&&&&&&&&&&& 3 &&&&&&&&&&&&" - print @under_vlans - return if @under_vlans.empty? - print " &&&&&&&&&&&& 4 &&&&&&&&&&&&" - - _xml_rm_under_vlans( xml, @under_vlans ) - print "\n ^^^^^^^^^^^ exiting xml_on_delete ^^^^^^^^^^^\n" - end - - ### --------------------------------------------------------------- - ### XML property writers - ### --------------------------------------------------------------- - - def xml_at_here( xml ) - print "\n ************** inside xml_at_here *************\n" - print xml.to_xml - @ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface') - @ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config - print "@ifd:" - print @ifd - xml.family { - xml.send(:'bridge') { - print "xml after removing ifd is: ",xml - return xml - } - } - end - - def xml_build_change( nop = nil ) - @under_vlans ||= [] # handles case for create'd port - - if mode_changed? - @should[:untagged_vlan] ||= @has[:untagged_vlan] - end - - super xml_at_here( xml_at_top ) - end - - ## ---------------------------------------------------------------- - ## :description - ## ---------------------------------------------------------------- - - ## overload default method since we need to "up-out" of the - ## ethernet-switching stanza - - def xml_change_description( xml ) - unit = xml.parent.xpath('ancestor::unit')[0] - Nokogiri::XML::Builder.with( unit ){ |x| - xml_set_or_delete( x, 'description', @should[:description] ) - } - end - - ## ---------------------------------------------------------------- - ## :vlan_tagging - ## ---------------------------------------------------------------- - - def xml_change_vlan_tagging( xml ) - print "\n\n ******************* xml_change_vlan_tagging *******************\n\n xml" - print xml.to_xml - port_mode = should_trunk? ? 'trunk' : 'access' - xml.send(:'interface-mode', port_mode ) - - # when the vlan_tagging value changes then this method - # will trigger updates to the untagged_vlan and tagged_vlans - # resource values as well. - # !!! DO NOT SWAP THIS ORDER untagged processing *MUST* BE FIRST! - - upd_untagged_vlan( xml ) - upd_tagged_vlans( xml ) - - return true - end - - ## ---------------------------------------------------------------- - ## :tagged_vlans - ## ---------------------------------------------------------------- - - def xml_change_tagged_vlans( xml ) - print "\n ************** inside xml_change_tagged_vlans *************\n\nxml:" - print xml.to_xml - return false if mode_changed? - upd_tagged_vlans( xml ) - end - - def upd_tagged_vlans( xml ) - print "\n ************** inside upd_tagged_vlans *************\n\n xml:" - print xml - return false unless should_trunk? - - print @should[:tagged_vlans] - print @has[:tagged_vlans] - - @should[:tagged_vlans] = @should[:tagged_vlans].to_set if @should[:tagged_vlans].kind_of? Array - @has[:tagged_vlans] = @has[:tagged_vlans].to_set if @has[:tagged_vlans].kind_of? Array - - v_should = @should[:tagged_vlans] || Set.new - v_has = @has[:tagged_vlans] || Set.new - - print "hiiiiii" - print v_should - print v_has - del = v_has - v_should - add = v_should - v_has - - print "add and del is: ", add, del - - add.each do |n| - # Display the element. - puts "add value is:", n - end - - del_under_vlans = del & @under_vlans - print "hello=========" - unless del_under_vlans.empty? - del = del ^ @under_vlans - _xml_rm_under_vlans( xml, del_under_vlans ) - @under_vlans = [] - end - puts "adds size is",add.size() - - - if add or del - print "\n inside add or del \n" - #xml.send(:'vlan-id') { - # del.each { |v| xml.members v, Netconf::JunosConfig::DELETE } - # add.each { |v| xml.members v } - add.each {|v| print "\n %%%%%%%%%%%%%%%%%% _vlan_name_to_tag_id( v ) \n", _vlan_name_to_tag_id( v )} - del.each{|v| xml.send(:'vlan-id-list', _vlan_name_to_tag_id( v ), Netconf::JunosConfig::DELETE)} - add.each{|v| xml.send( :'vlan-id-list', _vlan_name_to_tag_id(v) )} - print "\n %%%%%%% xml: \n", xml.to_xml - end - print "\n\n *************** exiting **************** \n\n" - return true - end - - ## ---------------------------------------------------------------- - ## :untagged_vlan - ## ---------------------------------------------------------------- - - def xml_change_untagged_vlan( xml ) - print "\n ************** inside xml_change_untagged_vlan *************\n\n xml:----" - print xml.to_xml - return false if mode_changed? - upd_untagged_vlan( xml ) - end - - def upd_untagged_vlan( xml ) - print "\n ************** inside upd_untagged_vlan *************\n\n xml:" - print xml.to_xml - self.class.change_untagged_vlan( self, xml ) - end - -end - -##### --------------------------------------------------------------- -##### Class methods for handling state-transitions between -##### configurations (tagged/untagged) -##### --------------------------------------------------------------- - -class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN - - # creating some class definitions ... - # this is a bit complicated because we need to handle port-mode - # change transitions; basically dealing with the fact that - # trunk ports use 'native-vlan-id' and access ports have a - # vlan member definition; i.e. they don't use native-vlan-id, ugh. - # Rather than doing all this logic as if/then/else statements, - # I've opted to using a proc jump-table technique. Lessons - # learned from lots of embedded systems programming :-) - - def self.init_jump_table - - # auto-hash table, majik! - hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)})) - - # ------------------------------------------------------------------ - # - jump table for handling various untagged vlan change use-cases - # ------------------------------------------------------------------ - # There are three criteria for selection: - # | is_trunk | will_trunk | no_untg | - # ------------------------------------------------------------------ - - # - will not have untagged vlan - hash[false][false][true] = self.method(:ac_ac_nountg) - hash[false][true][true] = self.method(:ac_tr_nountg) - hash[true][false][true] = self.method(:tr_ac_nountg) - hash[true][true][true] = self.method(:tr_tr_nountg) - - # - will have untagged vlan - hash[false][false][false] = self.method(:ac_ac_untg) - hash[false][true][false] = self.method(:ac_tr_untg) - hash[true][false][false] = self.method(:tr_ac_untg) - hash[true][true][false] = self.method(:tr_tr_untg) - - hash - end - - ### invoke the correct method from the jump table - ### based on the three criteria to select the action - - def self.change_untagged_vlan( this, xml ) - print "\n\n ********** inside change_untagged_vlan *************\n\n" - @@ez_l2_jmptbl ||= init_jump_table - print "\n @@ez_l2_jmptbl: ",@@ez_l2_jmptbl - proc = @@ez_l2_jmptbl[this.is_trunk?][this.should_trunk?][this.should[:untagged_vlan].nil?] - print "\n proc:",proc - proc.call( this, xml ) - end - - ### ------------------------------------------------------------- - ### The following are all the change transition functions for - ### each of the use-cases - ### ------------------------------------------------------------- - - def self.ac_ac_nountg( this, xml ) - print "\n !!!!!!!!!!! inside ac_ac_nountg !!!!!!!!!!!!!!!\n\n\n" - #^^^^^^^ create log - #NetdevJunos::Log.debug "ac_ac_nountg" - # @@@ a port *MUST* be assigned to a vlan in access mode on MX. - # @@@ generate an error! - raise Junos::Ez::NoProviderError, "a port *MUST* be assigned to a vlan in access mode on MX." - #raise "ERROR!!! a port *MUST* be assigned to a vlan in access mode on MX." - end - - ########## need to see################# - def self.ac_tr_nountg( this, xml ) - print "\n ******** inside ac_tr_nountg ********\n" - #unless (untg_vlan = this.has[:untagged_vlan]).nil? - # this._xml_rm_ac_untagged_vlan( xml ) - #end - #no action needed handled already - print "xml is:", xml.to_xml - end - ######################################### - - def self.tr_ac_nountg( this, xml ) - print "\n ******** inside tr_ac_nountg ********\n" - #this._delete_native_vlan_id( xml ) - #this._xml_rm_these_vlans( xml, this.has[:tagged_vlans ] ) if this.has[:tagged_vlans] - print "port must be assigned to vlan in access mode on MX" - raise Junos::Ez::NoProviderError, "port must be assigned to vlan in access mode on MX" - #raise "ERROR!! untagged_vlan missing, port must be assigned to a VLAN" - end - - def self.tr_tr_nountg( this, xml ) - print "\n ******** inside tr_tr_nountg ********\n" - this._delete_native_vlan_id( xml ) - print "xml is: ", xml.to_xml - end - - ## ---------------------------------------------------------------- - ## transition where port WILL-HAVE untagged-vlan - ## ---------------------------------------------------------------- - - ## setting untagged vlan id ######### - #######working######### - def self.ac_ac_untg( this, xml ) - print "\n ******** inside ac_ac_untg ********\n" - #this._xml_rm_ac_untagged_vlan( xml ) - print "\n xml is: ",xml.to_xml - print this.should[:untagged_vlan] - vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] ) - xml.send :'vlan-id', vlan_id - #xml.send :'vlan-id', (this._vlan_name_to_tag_id(this.should[:untagged_vlan])) - #xml.members this.should[:untagged_vlan] - #this._vlan_name_to_tag_id(this.should[:untagged_vlan]) - # print "hello: ",this._vlan_name_to_tag_id(this.should[:untagged_vlan]) - print "\n xml after vlan is: ",xml.to_xml - end - ###########working################# - - def self.ac_tr_untg( this, xml ) - print "\n inside ac_tr_untg \n" - # move untagged vlan to native-vlan-id ... - was_untg_vlan = this.has[:untagged_vlan] - this._set_native_vlan_id( xml, this.should[:untagged_vlan] ) - this._xml_rm_ac_untagged_vlan( xml ) if was_untg_vlan - end - - def self.tr_ac_untg( this, xml ) - print "\n ******** inside tr_ac_untg ********\n" - this._delete_native_vlan_id( xml ) - #this._xml_rm_these_vlans( xml, this.has[:tagged_vlans ] ) if this.has[:tagged_vlans] - #this._set_vlan_id(xml) - vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] ) - xml.send( :'vlan-id', vlan_id ) - print "xml: ", xml.to_xml - end - - def self.tr_tr_untg( this, xml ) - print "\n\n *********inside tr_tr_untg************\n\n" - print "xml: ", xml.to_xml - this._set_native_vlan_id(xml, this.should[:untagged_vlan]) - print "\n @@@@@@@@ xml is : ", xml - end - -end - -##### --------------------------------------------------------------- -##### Provider collection methods -##### --------------------------------------------------------------- - -class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN - - def build_list - print "\n\n ********** inside build_list ****************\n\n" - begin - got = @ndev.rpc.get_bridge_instance_information( :brief => true) - rescue => e - # in this case, no ethernet-switching is enabled so return empty list - return [] - end - got.xpath('//l2iff-interface-name').collect{ |ifn| ifn.text.split('.')[0] } - end - - def build_catalog - print "\n\n************ inside build_catalog *************\n\n" - @catalog = {} - return @catalog if list!.empty? - - list.each do |ifs_name| - @ndev.rpc.get_configuration{ |xml| - xml.interfaces { - xml_at_element_top( xml, ifs_name ) - } - }.xpath('interfaces/interface').each do |ifs_xml| - @catalog[ifs_name] = {} - unit = xml_get_has_xml( ifs_xml ) - xml_read_parser( unit, @catalog[ifs_name] ) - end - end - - @catalog - end - -end - -##### --------------------------------------------------------------- -##### !!!!! PRIVATE METHODS !!!! -##### --------------------------------------------------------------- - -class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN - private - - def _get_eth_port_vlans_h( ifs_name ) - print "\n********* inside _get_eth_port_vlans_h ****************\n" - got = @ndev.rpc.get_bridge_instance_information(:interface => ifs_name) - ret_h = {:untagged => nil, :tagged => Set.new } - got.xpath('//l2ng-l2ald-iff-interface-entry').each do |vlan| - # one of the node-set elements (the first one?) contains the interface name. - # this doesn't have any VLAN information, so skip it. - next if vlan.xpath('l2iff-interface-name') - - vlan_name = vlan.xpath('//l2rtb-bridge-vlan').text.strip - if vlan.xpath('//l2rtb-interface-vlan-member-tagness') - tgdy = vlan.xpath('//l2rtb-interface-vlan-member-tagness').text.strip - if tgdy == 'untagged' - ret_h[:untagged] = vlan_name - else - ret_h[:tagged] << vlan_name - end - else - ret_h[:tagged]< name + + xml_when_item(f_eth.xpath('ancestor::interface/native-vlan-id')){ |i| + as_hash[:untagged_vlan] = _vlan_tag_id_to_name( i.text.chomp, as_hash ) + } + end + + ### --------------------------------------------------------------- + ### XML on_create, on_delete handlers + ### --------------------------------------------------------------- + + ## overload the xml_on_delete method since we may need + ## to do some cleanup work in the [edit vlans] stanza + + def xml_on_delete( xml ) + @ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface') + @ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config + ## need to add check if any native-vlan-id is present or not (untagged vlan)##### + if is_trunk? and @ifd.xpath('//native-vlan-id') + _delete_native_vlan_id( xml ) + end + + return unless @under_vlans + return if @under_vlans.empty? + + _xml_rm_under_vlans( xml, @under_vlans ) + end + + ### --------------------------------------------------------------- + ### XML property writers + ### --------------------------------------------------------------- + + def xml_at_here( xml ) + @ifd = xml.instance_variable_get(:@parent).at_xpath('ancestor::interface') + @ifd.xpath('//native-vlan-id').remove ## remove the element from the get-config + xml.family { + xml.send(:'bridge') { + return xml + } + } + end + + def xml_build_change( nop = nil ) + @under_vlans ||= [] # handles case for create'd port + + if mode_changed? + @should[:untagged_vlan] ||= @has[:untagged_vlan] + end + + super xml_at_here( xml_at_top ) + end + + ## ---------------------------------------------------------------- + ## :description + ## ---------------------------------------------------------------- + + ## overload default method since we need to "up-out" of the + + def xml_change_description( xml ) + unit = xml.parent.xpath('ancestor::unit')[0] + Nokogiri::XML::Builder.with( unit ){ |x| + xml_set_or_delete( x, 'description', @should[:description] ) + } + end + + ## ---------------------------------------------------------------- + ## :vlan_tagging + ## ---------------------------------------------------------------- + + def xml_change_vlan_tagging( xml ) + port_mode = should_trunk? ? 'trunk' : 'access' + xml.send(:'interface-mode', port_mode ) + + # when the vlan_tagging value changes then this method + # will trigger updates to the untagged_vlan and tagged_vlans + # resource values as well. + # !!! DO NOT SWAP THIS ORDER untagged processing *MUST* BE FIRST! + + upd_untagged_vlan( xml ) + upd_tagged_vlans( xml ) + + return true + end + + def set_ifd_trunking( xml, should_trunk ) + par = xml.instance_variable_get(:@parent) + Nokogiri::XML::Builder.with( par.at_xpath( 'ancestor::interface' )) do |dot| + if should_trunk + dot.send( :'flexible-vlan-tagging' ) + dot.send( :'encapsulation', 'flexible-ethernet-services' ) + else + dot.send( :'flexible-vlan-tagging', Netconf::JunosConfig::DELETE ) + dot.send( :'encapsulation', Netconf::JunosConfig::DELETE ) + end + end +end + + ## ---------------------------------------------------------------- + ## :tagged_vlans + ## ---------------------------------------------------------------- + + def xml_change_tagged_vlans( xml ) + return false if mode_changed? + upd_tagged_vlans( xml ) + end + + def upd_tagged_vlans( xml ) + return false unless should_trunk? + + + @should[:tagged_vlans] = @should[:tagged_vlans].to_set if @should[:tagged_vlans].kind_of? Array + @has[:tagged_vlans] = @has[:tagged_vlans].to_set if @has[:tagged_vlans].kind_of? Array + + v_should = @should[:tagged_vlans] || Set.new + v_has = @has[:tagged_vlans] || Set.new + + del = v_has - v_should + add = v_should - v_has + + + del_under_vlans = del & @under_vlans + unless del_under_vlans.empty? + del = del ^ @under_vlans + _xml_rm_under_vlans( xml, del_under_vlans ) + @under_vlans = [] + end + + if add or del + del.each{|v| xml.send(:'vlan-id-list', _vlan_name_to_tag_id( v ), Netconf::JunosConfig::DELETE)} + add.each{|v| xml.send( :'vlan-id-list', _vlan_name_to_tag_id(v) )} + end + return true + end + + ## ---------------------------------------------------------------- + ## :untagged_vlan + ## ---------------------------------------------------------------- + + def xml_change_untagged_vlan( xml ) + return false if mode_changed? + upd_untagged_vlan( xml ) + end + + def upd_untagged_vlan( xml ) + self.class.change_untagged_vlan( self, xml ) + end + +end + +##### --------------------------------------------------------------- +##### Class methods for handling state-transitions between +##### configurations (tagged/untagged) +##### --------------------------------------------------------------- + +class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN + + # creating some class definitions ... + # this is a bit complicated because we need to handle port-mode + # change transitions; basically dealing with the fact that + # trunk ports use 'native-vlan-id' and access ports have a + # vlan member definition; i.e. they don't use native-vlan-id, ugh. + # Rather than doing all this logic as if/then/else statements, + # I've opted to using a proc jump-table technique. Lessons + # learned from lots of embedded systems programming :-) + + def self.init_jump_table + + # auto-hash table, majik! + hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)})) + + # ------------------------------------------------------------------ + # - jump table for handling various untagged vlan change use-cases + # ------------------------------------------------------------------ + # There are three criteria for selection: + # | is_trunk | will_trunk | no_untg | + # ------------------------------------------------------------------ + + # - will not have untagged vlan + hash[false][false][true] = self.method(:ac_ac_nountg) + hash[false][true][true] = self.method(:ac_tr_nountg) + hash[true][false][true] = self.method(:tr_ac_nountg) + hash[true][true][true] = self.method(:tr_tr_nountg) + + # - will have untagged vlan + hash[false][false][false] = self.method(:ac_ac_untg) + hash[false][true][false] = self.method(:ac_tr_untg) + hash[true][false][false] = self.method(:tr_ac_untg) + hash[true][true][false] = self.method(:tr_tr_untg) + + hash + end + + ### invoke the correct method from the jump table + ### based on the three criteria to select the action + + def self.change_untagged_vlan( this, xml ) + @@ez_l2_jmptbl ||= init_jump_table + proc = @@ez_l2_jmptbl[this.is_trunk?][this.should_trunk?][this.should[:untagged_vlan].nil?] + proc.call( this, xml ) + end + + ### ------------------------------------------------------------- + ### The following are all the change transition functions for + ### each of the use-cases + ### ------------------------------------------------------------- + + def self.ac_ac_nountg( this, xml ) + #NetdevJunos::Log.debug "ac_ac_nountg" + # @@@ a port *MUST* be assigned to a vlan in access mode on MX. + # @@@ generate an error! + raise Junos::Ez::NoProviderError, "a port *MUST* be assigned to a vlan in access mode on MX." + end + + def self.ac_tr_nountg( this, xml ) + #no action needed handled already + end + + def self.tr_ac_nountg( this, xml ) + # @@@ a port *MUST* be assigned to a vlan in access mode on MX. + # @@@ generate an error! + raise Junos::Ez::NoProviderError, "a port *MUST* be assigned to vlan in access mode on MX" + end + + def self.tr_tr_nountg( this, xml ) + this._delete_native_vlan_id( xml ) + end + + ## ---------------------------------------------------------------- + ## transition where port WILL-HAVE untagged-vlan + ## ---------------------------------------------------------------- + + def self.ac_ac_untg( this, xml ) + vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] ) + xml.send :'vlan-id', vlan_id + end + + def self.ac_tr_untg( this, xml ) + was_untg_vlan = this.has[:untagged_vlan] + this._set_native_vlan_id( xml, this.should[:untagged_vlan] ) + this._xml_rm_ac_untagged_vlan( xml ) if was_untg_vlan + end + + def self.tr_ac_untg( this, xml ) + this._delete_native_vlan_id( xml ) + vlan_id = this._vlan_name_to_tag_id( this.should[:untagged_vlan] ) + xml.send( :'vlan-id', vlan_id ) + end + + def self.tr_tr_untg( this, xml ) + this._set_native_vlan_id(xml, this.should[:untagged_vlan]) + end + +end + +##### --------------------------------------------------------------- +##### Provider collection methods +##### --------------------------------------------------------------- + +class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN + + def build_list + begin + got = @ndev.rpc.get_bridge_instance_information( :brief => true) + rescue => e + # in this case, no ethernet-switching is enabled so return empty list + return [] + end + got.xpath('//l2iff-interface-name').collect{ |ifn| ifn.text.split('.')[0] } + end + + def build_catalog + @catalog = {} + return @catalog if list!.empty? + list.each do |ifs_name| + @ndev.rpc.get_configuration{ |xml| + xml.interfaces { + xml_at_element_top( xml, ifs_name ) + } + }.xpath('interfaces/interface').each do |ifs_xml| + @catalog[ifs_name] = {} + unit = xml_get_has_xml( ifs_xml ) + xml_read_parser( unit, @catalog[ifs_name] ) + end + end + + @catalog + end + +end + +##### --------------------------------------------------------------- +##### !!!!! PRIVATE METHODS !!!! +##### --------------------------------------------------------------- + +class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN + private + + def _get_eth_port_vlans_h( ifs_name ) + got = @ndev.rpc.get_bridge_instance_information(:interface => ifs_name) + ret_h = {:untagged => nil, :tagged => Set.new } + got.xpath('//l2ng-l2ald-iff-interface-entry').each do |vlan| + # one of the node-set elements (the first one?) contains the interface name. + # this doesn't have any VLAN information, so skip it. + next if vlan.xpath('l2iff-interface-name') + + vlan_name = vlan.xpath('//l2rtb-bridge-vlan').text.strip + if vlan.xpath('//l2rtb-interface-vlan-member-tagness') + tgdy = vlan.xpath('//l2rtb-interface-vlan-member-tagness').text.strip + if tgdy == 'untagged' + ret_h[:untagged] = vlan_name + else + ret_h[:tagged] << vlan_name + end + else + ret_h[:tagged]< Date: Wed, 15 Jul 2015 16:53:03 +0530 Subject: [PATCH 03/33] vlan delete --- lib/junos-ez/vlans/bridge_domain.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/junos-ez/vlans/bridge_domain.rb b/lib/junos-ez/vlans/bridge_domain.rb index bf3d2fd..50ed830 100644 --- a/lib/junos-ez/vlans/bridge_domain.rb +++ b/lib/junos-ez/vlans/bridge_domain.rb @@ -21,9 +21,13 @@ def xml_read! return nil unless (@has_xml = cfg_xml.xpath('//domain')[0]) xml_read_parser( @has_xml, @has ) end + + def xml_get_has_xml( xml ) + xml.xpath('//domain')[0] + end def xml_read_parser( as_xml, as_hash ) - status_from_junos( as_xml, as_hash ) + set_has_status( as_xml, as_hash ) as_hash[:vlan_id] = as_xml.xpath('vlan-id').text.to_i as_hash[:description] = as_xml.xpath('description').text as_hash[:no_mac_learning] = as_xml.xpath('bridge-options/no-mac-learning').empty? ? :disable : :enable From 7c6e64ab62dcea88a4b26dedf26aad4c10e560e9 Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Wed, 22 Jul 2015 17:51:35 +0530 Subject: [PATCH 04/33] lags for gigether interface --- lib/junos-ez/lag_ports.rb | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/junos-ez/lag_ports.rb b/lib/junos-ez/lag_ports.rb index 15846a5..d3bcf51 100644 --- a/lib/junos-ez/lag_ports.rb +++ b/lib/junos-ez/lag_ports.rb @@ -43,8 +43,11 @@ def xml_at_top ### --------------------------------------------------------------- def xml_get_has_xml( xml ) - @ifd_ether_options = 'ether-options' # @@@ hack for now - + if ndev.facts[:ifd_style] == "CLASSIC" + @ifd_ether_options = 'gigether-options' + else + @ifd_ether_options = 'ether-options' + end xml.xpath('//interface')[0] end @@ -70,9 +73,27 @@ def xml_read_parser( as_xml, as_hash ) ### --------------------------------------------------------------- ### XML property writers ### --------------------------------------------------------------- - + def update_ifd_should() + if @should[:links].empty? + raise Junos::Ez::NoProviderError, "\n *links* are compulsory for creating lag interface!!! \n" + else + ether_option = @should[:links][0].to_s + @ifd_ether_options = (ether_option.start_with? 'fe-') ? 'fastether-options' : 'gigether-options' + end + end + + def update_ifd_has() + @has[:links] = @has[:links].to_a + if @has[:links].empty? + raise Junos::Ez::NoProviderError, "\n Either lag interface is not created or links associated with given lag interface is not supported \n" + else + ether_option = @has[:links][0].to_s + @ifd_ether_options = (ether_option.start_with? 'fe-') ? 'fastether-options' : 'gigether-options' + end + end + def xml_change_links( xml ) - + update_ifd_should() @should[:links] = @should[:links].to_set if @should[:links].kind_of? Array has = @has[:links] || Set.new @@ -144,7 +165,7 @@ def xml_on_create( xml ) ### --------------------------------------------------------------- def xml_on_delete( xml ) - + update_ifd_has() par = xml.instance_variable_get(:@parent) dot_ifd = par.at_xpath('ancestor::interfaces') From f99f9b86d013dd768cad1e576ff777b338837da5 Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Tue, 11 Aug 2015 14:45:44 +0530 Subject: [PATCH 05/33] solving duplicate declaration --- lib/junos-ez/lag_ports.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/junos-ez/lag_ports.rb b/lib/junos-ez/lag_ports.rb index d3bcf51..63e2e17 100644 --- a/lib/junos-ez/lag_ports.rb +++ b/lib/junos-ez/lag_ports.rb @@ -41,6 +41,11 @@ def xml_at_top ### --------------------------------------------------------------- ### XML property readers ### --------------------------------------------------------------- + + def xml_config_read! + database = {'database' => 'committed'} + @ndev.rpc.get_configuration(xml_at_top, database) + end def xml_get_has_xml( xml ) if ndev.facts[:ifd_style] == "CLASSIC" From 6b1a31b86317ff17d9d6b8b8a8dd34b29be52871 Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Wed, 19 Aug 2015 20:15:56 +0530 Subject: [PATCH 06/33] netdev_group template add --- lib/junos-ez/group.rb | 208 +++++++++++++++++++++++++++++++++++++++++ lib/junos-ez/stdlib.rb | 1 + 2 files changed, 209 insertions(+) create mode 100644 lib/junos-ez/group.rb diff --git a/lib/junos-ez/group.rb b/lib/junos-ez/group.rb new file mode 100644 index 0000000..59fd27e --- /dev/null +++ b/lib/junos-ez/group.rb @@ -0,0 +1,208 @@ +require "junos-ez/provider" + +module Junos::Ez::Group + + PROPERTIES = [ + :format, # [:set, :text, :xml] + :path, # Configuration file path +] + + def self.Provider( ndev, varsym ) + newbie = Junos::Ez::Group::Provider::new( ndev ) + newbie.properties = Junos::Ez::Provider::PROPERTIES + PROPERTIES + Junos::Ez::Provider.attach_instance_variable( ndev, varsym, newbie ) + end + + class Provider < Junos::Ez::Provider::Parent + # common parenting goes here ... if we were to + # subclass the objects ... not doing that now + end + +end + +class Junos::Ez::Group::Provider + + ### --------------------------------------------------------------- + ### XML top placement + ### --------------------------------------------------------------- + + def xml_at_top + xml = Nokogiri::XML::Builder.new {|xml| xml.configuration { + xml.groups { + xml.name @name + return xml + } + }} + end + + ### --------------------------------------------------------------- + ### XML property readers + ### --------------------------------------------------------------- + + def xml_get_has_xml( xml ) + xml.xpath('//groups')[0] + end + + def xml_read_parser( as_xml, as_hash ) + set_has_status( as_xml, as_hash ) + + grp = as_xml.xpath('name').text + as_hash[:name] = grp unless grp.empty? + + end + + + ### --------------------------------------------------------------- + ### XML property writers + ### --------------------------------------------------------------- + + def xml_change_path( xml ) + end + + def xml_change_format( xml ) + end + + ### --------------------------------------------------------------- + ### XML on-create + ### --------------------------------------------------------------- + + def xml_on_create( xml ) + end + + ### --------------------------------------------------------------- + ### XML on-delete + ### --------------------------------------------------------------- + def xml_on_delete( xml ) + end + + def write_xml_config!( xml, opts = {} ) + if (@should[:_exist] == true) + _load ( xml ) + @should[:format] = 'xml' unless @should[:format] + begin + attr = {} + attr[:action] = 'replace' + attr[:format] = @should[:format].to_s + result = @ndev.rpc.load_configuration( @config.to_s, attr ) + rescue Netconf::RpcError => e + errs = e.rsp.xpath('//rpc-error[error-severity = "error"]') + raise e unless errs.empty? + e.rsp + else + result + end + else + #Junos::Ez::Provider::Parent.instance_method(:write_xml_config!(xml)).bind(self).call + super(xml) + end + _apply_group + end + + def write! + return nil if @should.empty? + + @should[:_exist] ||= true + @should[:_active] ||= :true + # load the conifguration from file and apply under group + # hirerachy + rsp = write_xml_config!( xml_at_top.doc.root ) + + # copy the 'should' values into the 'has' values now that + # they've been written back to Junos + + @has.merge! @should + @should.clear + + return true + end + +end + + +##### --------------------------------------------------------------- +##### Provider collection methods +##### --------------------------------------------------------------- + +class Junos::Ez::Group::Provider + + def build_list + grp_cfgs = @ndev.rpc.get_configuration{|xml| + xml.send(:'groups') + }.xpath('groups/name').collect do |item| + item.text + end + return grp_cfgs + end + + def build_catalog + return @catalog if list!.empty? + list.each do |grp_name| + @ndev.rpc.get_configuration{ |xml| + xml.gropus { + xml.name grp_name + } + }.xpath('groups').each do |as_xml| + @catalog[grp_name] = {} + xml_read_parser( as_xml, @catalog[grp_name] ) + end + end + @catalog + end +end + +##### --------------------------------------------------------------- +##### _PRIVATE methods +##### --------------------------------------------------------------- + +class Junos::Ez::Group::Provider + + def _load ( xml ) + return @config = nil if ( @should[:_exist] == false ) + admin = '' + if @should[:format].to_s == 'set' + @config = "\ndelete groups #{@name}\n" + + "edit groups #{@name}\n" + + File.read( @should[:path] ) + admin = @should[:_active] == :false ? 'deactivate' : 'activate' + @config += "\nquit\n" + @config += "\n#{admin} groups #{@name}" + + elsif @should[:format].to_s == 'text' + admin = @should[:_active] == :false ? 'inactive' : 'active' + admin += ": " unless admin.empty? + @config = "groups {\n#{admin} replace: #{@name} {\n" + + File.read( @should[:path] ) + "\n}\n}" + + elsif @should[:format].to_s == 'xml' + xml.at_xpath('groups') << File.read( @should[:path]) + @config = xml + end + return @config + end + + def _apply_group + cfg = Netconf::JunosConfig.new(:TOP) + xml = cfg.doc + Nokogiri::XML::Builder.with( xml.at_xpath( 'configuration' )) do |dot| + if @config and @should[:_active] == :true + dot.send :'apply-groups', @name + else + dot.send :'apply-groups', @name, Netconf::JunosConfig::DELETE + end + end + begin + attr = {} + attr[:action] = 'replace' + attr[:format] = 'xml' + result = @ndev.rpc.load_configuration( xml, attr ) + rescue Netconf::RpcError => e + errs = e.rsp.xpath('//rpc-error[error-severity = "error"]') + raise e unless errs.empty? + e.rsp + else + result + end + end + +end + diff --git a/lib/junos-ez/stdlib.rb b/lib/junos-ez/stdlib.rb index 3c1c2b1..8ecd286 100644 --- a/lib/junos-ez/stdlib.rb +++ b/lib/junos-ez/stdlib.rb @@ -7,6 +7,7 @@ require 'junos-ez/l2_ports' # switch ports require 'junos-ez/ip_ports' # ip ports (v4) require 'junos-ez/lag_ports' # Link Aggregation Groups +require 'junos-ez/group' # ------------------------------------------------------------------- # utility libraries, not providers From fd19c2160ced49d8500a097487c5267a51fc806e Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Wed, 19 Aug 2015 20:18:30 +0530 Subject: [PATCH 07/33] Update group.rb --- lib/junos-ez/group.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/junos-ez/group.rb b/lib/junos-ez/group.rb index 59fd27e..5389b53 100644 --- a/lib/junos-ez/group.rb +++ b/lib/junos-ez/group.rb @@ -92,7 +92,6 @@ def write_xml_config!( xml, opts = {} ) result end else - #Junos::Ez::Provider::Parent.instance_method(:write_xml_config!(xml)).bind(self).call super(xml) end _apply_group @@ -203,6 +202,5 @@ def _apply_group result end end - end From e3175cef83bef41f3e36b60ff56e9891e4be88c0 Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Tue, 8 Sep 2015 16:14:40 +0530 Subject: [PATCH 08/33] solving rerunning lag_interface --- lib/junos-ez/lag_ports.rb | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/junos-ez/lag_ports.rb b/lib/junos-ez/lag_ports.rb index 63e2e17..d6daf1a 100644 --- a/lib/junos-ez/lag_ports.rb +++ b/lib/junos-ez/lag_ports.rb @@ -37,6 +37,24 @@ def xml_at_top }} }} end + + ###----------------------------------------------------------- + ###----------------------------------------------------------- + ### utilities + ###----------------------------------------------------------- + + def get_cookie_links( cfg ) + cfg.xpath( "apply-macro[name = 'netdev_lag[:links]']/data/name" ).collect { |n| n.text } + end + + def set_cookie_links( cfg ) + cfg.send(:'apply-macro', Netconf::JunosConfig::REPLACE ) { + cfg.name 'netdev_lag[:links]' + should[:links].each{ |ifd| + cfg.data { cfg.name ifd } + } + } + end ### --------------------------------------------------------------- ### XML property readers @@ -61,7 +79,7 @@ def xml_read_parser( as_xml, as_hash ) # property :links ae_name = as_xml.xpath('name').text - as_hash[:links] = Set.new(_get_port_list( ae_name )) + as_hash[:links] = Set.new(get_cookie_links(as_xml)) # property :lacp ae_opts = as_xml.xpath('aggregated-ether-options') @@ -104,6 +122,8 @@ def xml_change_links( xml ) has = @has[:links] || Set.new should = @should[:links] || Set.new + set_cookie_links( xml ) + del = has - should add = should - has From b157b991dae745feb746ce975a36f0dbddbaeadb Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Thu, 24 Sep 2015 11:05:34 +0530 Subject: [PATCH 09/33] modified addition of tagged vlans --- lib/junos-ez/l2_ports/bridge_domain.rb | 52 +++++++++----------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/lib/junos-ez/l2_ports/bridge_domain.rb b/lib/junos-ez/l2_ports/bridge_domain.rb index ce23e7e..9f90f19 100644 --- a/lib/junos-ez/l2_ports/bridge_domain.rb +++ b/lib/junos-ez/l2_ports/bridge_domain.rb @@ -34,7 +34,6 @@ def xml_at_element_top( xml, name ) def xml_get_has_xml( xml ) # second unit contains the family/bridge-domains stanza got = xml.xpath('//unit')[0] - # if this resource doesn't exist we need to default some # values into has/should variables unless got @@ -44,7 +43,7 @@ def xml_get_has_xml( xml ) got end - def xml_read_parser( as_xml, as_hash ) + def xml_read_parser( as_xml, as_hash ) ## reading is anchored at the [... unit 0 ...] level set_has_status( as_xml, as_hash ) @@ -72,22 +71,21 @@ def xml_read_parser( as_xml, as_hash ) end # --- trunk port - - as_hash[:untagged_vlan] ||= eth_port_vlans[:untagged] - as_hash[:tagged_vlans] = f_eth.xpath('domain/vlan-id-list').collect { |v| v.text.chomp }.to_set + as_hash[:untagged_vlan] ||= eth_port_vlans[:untagged] + as_hash[:tagged_vlans] = f_eth.xpath('//bridge/vlan-id-list').collect { |v| v.text.chomp }.to_set (eth_port_vlans[:tagged] - as_hash[:tagged_vlans]).each do |vlan| as_hash[:tagged_vlans] << vlan - @under_vlans << vlan + @under_vlans << vlan end - # native-vlan-id is set at the interface level, and is the VLAN-ID, not the vlan # name. So we need to do a bit of translating here. The *ASSUMPTION* is that the # native-vlan-id value is a given VLAN in the tagged_vlan list. So we will use # that list to do the reverse lookup on the tag-id => name - - xml_when_item(f_eth.xpath('ancestor::interface/native-vlan-id')){ |i| - as_hash[:untagged_vlan] = _vlan_tag_id_to_name( i.text.chomp, as_hash ) + as_hash[:tagged_vlans]= as_hash[:tagged_vlans].collect {|x| _vlan_tag_id_to_name(x)} + xml_when_item(f_eth.xpath('ancestor::interface/native-vlan-id')){ |i| + as_hash[:untagged_vlan] = _vlan_tag_id_to_name( i.text.chomp) } + as_hash[:tagged_vlans].delete(as_hash[:untagged_vlan]) end ### --------------------------------------------------------------- @@ -127,11 +125,9 @@ def xml_at_here( xml ) def xml_build_change( nop = nil ) @under_vlans ||= [] # handles case for create'd port - if mode_changed? @should[:untagged_vlan] ||= @has[:untagged_vlan] end - super xml_at_here( xml_at_top ) end @@ -189,10 +185,9 @@ def xml_change_tagged_vlans( xml ) upd_tagged_vlans( xml ) end - def upd_tagged_vlans( xml ) + def upd_tagged_vlans( xml ) return false unless should_trunk? - @should[:tagged_vlans] = @should[:tagged_vlans].to_set if @should[:tagged_vlans].kind_of? Array @has[:tagged_vlans] = @has[:tagged_vlans].to_set if @has[:tagged_vlans].kind_of? Array @@ -202,7 +197,6 @@ def upd_tagged_vlans( xml ) del = v_has - v_should add = v_should - v_has - del_under_vlans = del & @under_vlans unless del_under_vlans.empty? del = del ^ @under_vlans @@ -465,30 +459,20 @@ def _vlan_name_to_tag_id( vlan_name ) tag_id = @ndev.rpc.get_configuration { |xml| xml.send(:'bridge-domains') { xml.domain { xml.name vlan_name }} }.xpath('//vlan-id').text.chomp - raise ArgumentError, "VLAN '#{vlan_name}' not found" if tag_id.empty? return tag_id end - def _vlan_tag_id_to_name( tag_id, my_hash ) - # get the candidate configuration for each VLAN named in tagged_vlans and - # then map it to the corresponding vlan-id. this is not very effecient, but - # at present there is no other way without getting into a cache mech. - vlan_name = @ndev.rpc.get_configuration { |xml| - xml.send(:'bridge-domains') { - my_hash[:tagged_vlans].each do |v_name| - xml.domain { - xml.name v_name - xml.send(:'vlan-id') - } - end - } - }.xpath("//domain[vlan-id = '#{tag_id}']/name").text.chomp - - raise ArgumentError, "VLAN-ID '#{tag_id}' not found" if vlan_name.empty? - return vlan_name + + def _vlan_tag_id_to_name( vlan_id ) + tag_name = @ndev.rpc.get_configuration { |xml| + xml.send(:'bridge-domains') { xml.domain { xml.send(:'vlan-id', vlan_id)}} + }.xpath('//name').text.chomp + raise ArgumentError, "VLAN '#{vlan_id}' not found" if tag_name.empty? + return tag_name end - + + end class Junos::Ez::L2ports::Provider::BRIDGE_DOMAIN From 7891bff27aee3c7e1c06fe2d147c8e2f6f40d8ee Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Thu, 5 Nov 2015 16:12:08 +0530 Subject: [PATCH 10/33] resolving PR-1131912, for backup RE --- lib/junos-ez/facts/chassis.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/junos-ez/facts/chassis.rb b/lib/junos-ez/facts/chassis.rb index d9c2fef..0c1ca6f 100644 --- a/lib/junos-ez/facts/chassis.rb +++ b/lib/junos-ez/facts/chassis.rb @@ -1,6 +1,12 @@ Junos::Ez::Facts::Keeper.define( :chassis ) do |ndev, facts| inv_info = ndev.rpc.get_chassis_inventory + errs = inv_info.xpath('//output')[0] + + if errs.text.include? "This command can only be used on the master routing engine" + raise Junos::Ez::NoProviderError, "Chef can only be used on master routing engine !!" + end + chassis = inv_info.xpath('chassis') facts[:hardwaremodel] = chassis.xpath('description').text From bfa1380b0fae7469f8b455030b0295cff527bab9 Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Fri, 20 Nov 2015 14:25:20 +0530 Subject: [PATCH 11/33] resolving dual RE issue --- lib/junos-ez/facts/chassis.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/junos-ez/facts/chassis.rb b/lib/junos-ez/facts/chassis.rb index 0c1ca6f..d0e2b15 100644 --- a/lib/junos-ez/facts/chassis.rb +++ b/lib/junos-ez/facts/chassis.rb @@ -3,7 +3,7 @@ inv_info = ndev.rpc.get_chassis_inventory errs = inv_info.xpath('//output')[0] - if errs.text.include? "This command can only be used on the master routing engine" + if errs and errs.text.include? "This command can only be used on the master routing engine" raise Junos::Ez::NoProviderError, "Chef can only be used on master routing engine !!" end From a5eeb6fe0d2359c3d9e443c1af7c5082cb87415c Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Fri, 20 Nov 2015 14:30:05 +0530 Subject: [PATCH 12/33] Fix Issue #33 --- lib/junos-ez/facts/version.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/junos-ez/facts/version.rb b/lib/junos-ez/facts/version.rb index 934ac55..1cdd6e3 100644 --- a/lib/junos-ez/facts/version.rb +++ b/lib/junos-ez/facts/version.rb @@ -4,7 +4,11 @@ case f_persona when :MX - swver = ndev.rpc.command "show version invoke-on all-routing-engines" + begin + swver = ndev.rpc.command "show version invoke-on all-routing-engines" + rescue Netconf::RpcError + swver = ndev.rpc.command "show version" + end when :SWITCH ## most EX switches support the virtual-chassis feature, so the 'all-members' option would be valid ## in some products, this options is not valid (i.e. not vc-capable. so we're going to try for vc, and if that From 6916b2f704e4e2db41dfae0dc6b62c7641027050 Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Fri, 4 Dec 2015 10:49:24 +0530 Subject: [PATCH 13/33] adding fix for qfx devices --- lib/junos-ez/facts/switch_style.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/junos-ez/facts/switch_style.rb b/lib/junos-ez/facts/switch_style.rb index ad4f201..d14e497 100644 --- a/lib/junos-ez/facts/switch_style.rb +++ b/lib/junos-ez/facts/switch_style.rb @@ -9,9 +9,9 @@ case examine when /junosv-firefly/i :NONE - when /^(ex9)|(ex43)|(ocx)/i + when /^(ex)|(ocx)/i :VLAN_L2NG - when /^(qfx5)|(qfx3)/i + when /^(qfx)/i if facts[:version][0..3].to_f >= 13.2 :VLAN_L2NG else From 45b03131d9709dea23e9c3f80c511efee3897b4b Mon Sep 17 00:00:00 2001 From: Jainpriyal Date: Fri, 4 Dec 2015 11:25:36 +0530 Subject: [PATCH 14/33] resolving qfx issue --- lib/junos-ez/facts/switch_style.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/junos-ez/facts/switch_style.rb b/lib/junos-ez/facts/switch_style.rb index d14e497..da98f53 100644 --- a/lib/junos-ez/facts/switch_style.rb +++ b/lib/junos-ez/facts/switch_style.rb @@ -9,7 +9,7 @@ case examine when /junosv-firefly/i :NONE - when /^(ex)|(ocx)/i + when /^(ex9)|(ex43)|(ocx)/i :VLAN_L2NG when /^(qfx)/i if facts[:version][0..3].to_f >= 13.2 From d125350a896825e276d3a945f58457e0b0703d23 Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Wed, 23 Dec 2015 14:33:30 +0530 Subject: [PATCH 15/33] Fix issue #28 --- lib/junos-ez/facts/personality.rb | 10 +++++----- lib/junos-ez/facts/version.rb | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/junos-ez/facts/personality.rb b/lib/junos-ez/facts/personality.rb index 0b834ec..4d8c35d 100644 --- a/lib/junos-ez/facts/personality.rb +++ b/lib/junos-ez/facts/personality.rb @@ -6,19 +6,19 @@ examine = ( model != "Virtual Chassis" ) ? model : facts.select {|k,v| k.match(/^RE[0..9]+/) }.values[0][:model] facts[:personality] = case examine - when /^(EX)|(QFX)|(OCX)/ + when /^(EX)|(QFX)|(OCX)/i :SWITCH - when /^MX/ + when /^MX/i :MX - when /^vMX/ + when /^vMX/i facts[:virtual] = true :MX - when /SRX(\d){3}/ + when /SRX(\d){3}/i :SRX_BRANCH when /junosv-firefly/i facts[:virtual] = true :SRX_BRANCH - when /SRX(\d){4}/ + when /SRX(\d){4}/i :SRX_HIGHEND end diff --git a/lib/junos-ez/facts/version.rb b/lib/junos-ez/facts/version.rb index 1cdd6e3..d4fc740 100644 --- a/lib/junos-ez/facts/version.rb +++ b/lib/junos-ez/facts/version.rb @@ -30,9 +30,14 @@ swver_infos = swver.xpath('//software-information') swver_infos.each do |re_sw| re_name = re_sw.xpath('preceding-sibling::re-name').text.upcase - re_sw.xpath('package-information[1]/comment').text =~ /\[(.*)\]/ ver_key = ('version_' + re_name).to_sym - facts[ver_key] = $1 + + if re_sw.at_xpath('//junos-version') + facts[ver_key] = re_sw.xpath('//junos-version').text + else + re_sw.xpath('package-information[1]/comment').text =~ /\[(.*)\]/ + facts[ver_key] = $1 + end end master_id = f_master unless master_id.nil? @@ -41,9 +46,13 @@ facts[('version_' + "FPC" + master_id).to_sym] end else - junos = swver.xpath('//package-information[name = "junos"]/comment').text - junos =~ /\[(.*)\]/ - facts[:version] = $1 + if swver.at_xpath('//junos-version') + facts[:version] = swver.xpath('//junos-version').text + else + junos = swver.xpath('//package-information[name = "junos"]/comment').text + junos =~ /\[(.*)\]/ + facts[:version] = $1 + end end end From 2bccc425e979e2dabd0a855336c58754167279e2 Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Thu, 11 Feb 2016 10:59:32 +0530 Subject: [PATCH 16/33] Fix issue #42 --- lib/junos-ez/provider.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/junos-ez/provider.rb b/lib/junos-ez/provider.rb index 5091ff7..7a11b79 100644 --- a/lib/junos-ez/provider.rb +++ b/lib/junos-ez/provider.rb @@ -544,7 +544,7 @@ def write_xml_config!( xml, opts = {} ) action = {'action' => 'replace' } result = @ndev.rpc.load_configuration( xml, action ) rescue Netconf::RpcError => e - errs = e.rsp.xpath('//rpc-error[error-severity = "error"]') + errs = e.rsp.xpath('//rpc-error') raise e unless errs.empty? e.rsp else From 182687ad6c13ce9db11f719aabaf92e5a2c463e6 Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Fri, 26 Feb 2016 15:20:40 +0530 Subject: [PATCH 17/33] Update group.rb --- lib/junos-ez/group.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/junos-ez/group.rb b/lib/junos-ez/group.rb index 5389b53..b4cbb2b 100644 --- a/lib/junos-ez/group.rb +++ b/lib/junos-ez/group.rb @@ -137,7 +137,7 @@ def build_catalog return @catalog if list!.empty? list.each do |grp_name| @ndev.rpc.get_configuration{ |xml| - xml.gropus { + xml.groups { xml.name grp_name } }.xpath('groups').each do |as_xml| From d6a01aebcb078a534acf65349b0e76ab90d28342 Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Fri, 11 Mar 2016 11:59:16 +0530 Subject: [PATCH 18/33] Update to version 1.0.0 --- CHANGELOG.md | 23 +++++++++++- README.md | 13 +++++-- docs/Providers/.LAGports.md.swp | Bin 0 -> 12288 bytes docs/Providers/Group.md | 61 ++++++++++++++++++++++++++++++++ junos-ez-stdlib.gemspec | 4 +-- lib/junos-ez/group.rb | 2 +- lib/junos-ez/version.rb | 2 +- 7 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 docs/Providers/.LAGports.md.swp create mode 100644 docs/Providers/Group.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 47bb9ba..a4ae35a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,7 +63,28 @@ # 2013-Aug - 0.2.0: *in progres* + 0.2.0: Fixed issue #6. Added support for EX4300 platform. Added new provider for Link Aggregation Group resources (LAGports) + +# 2016-March + + 1.0.0 + - Fixed issues + Issue #17: Add support for OCX device + Issue #20: "under development" error is thrown while importing the interface_create recipe from the Chef-Server. + Issue #22: "netdev_vlan" resource action delete is not working fine while invoking from the JUNOS Chef-Client. + Issue #23: RPC command error: commit-configuration is getting thrown on Invoking the "netdev_lag" resource from + JUNOS Chef Client. + Issue #27: Duplicate declaration of lag configuration in a recipe is giving NoMethodError: undefined method + `properties' for nil:NilClass. + Issue #30: Error in rerunning netdev_lag interface. + Issue #33: undefined method `properties' for nil:NilClass error is thrown if the backup RE is unreachable. + Issue #35: Error in running chef client from Backup RE. + Issue #39: Getting 'Junos::Ez::NoProviderError' error on qfx device. + Issue #42: Raise exception to handle warnings in . + + -Enhancement + * Add support for configuring l2_interface on MX device. + * Add support for provider 'group' for configuring JUNOS groups. diff --git a/README.md b/README.md index 77d4f7c..eda435f 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ documentation on Providers/Resources, see the *docs* directory. - IPports: IP v4 port management - StaticHosts: Static Hosts [system static-host-mapping ...] - StaticRoutes: Static Routes [routing-options static ...] + - Group: JUNOS groups management # UTILITIES @@ -173,9 +174,15 @@ documentation on Providers/Resources, see the *docs* directory. * gem install junos-ez-stdlib # CONTRIBUTORS - - * Jeremy Schulman, @nwkautomaniac - * Ganesh Nalawade, @ganesh634 + Juniper Networks is actively contributing to and maintaining this repo. Please contact jnpr-community-netdev@juniper.net + for any queries. + + Contributors: + [John Deatherage](https://github.com/routelastresort), [Nitin Kumar](https://github.com/vnitinv) + [Priyal Jain](https://github.com/jainpriyal), [Ganesh Nalawade](https://github.com/ganeshnalawade) + + Former Contributors: + [Jeremy Schulman](https://github.com/jeremyschulman) # LICENSES diff --git a/docs/Providers/.LAGports.md.swp b/docs/Providers/.LAGports.md.swp new file mode 100644 index 0000000000000000000000000000000000000000..896aedc727433e5d8832db75638dd7bcab17fc35 GIT binary patch literal 12288 zcmeI2O>Z1E7{^_1ytG9iA;AHjZV*XIc6O715K}6;&?N*V%_=W#(JBz{jCa;$#$Js* zNjFs}Cpf`@0~b(xh67xI55ZReaRM%U00iRi*_R|J%ALw1{j!e7<9VK+UzBLwsb61S zrB{MQhU;<0O#9dCFDckU=fF?r82cXF2lv3|;4|1Z!1Lfa@GSV}QO5oTuYpTo0Xzeq27e*PKfxcs z<@+1(mp9-Icmv*mH{cC;1Kz-cYG4N!bLU5cy$Q4q z{^iOxD{s?fQnA<#Ql6N0g^N0FxPIJeRs0>=6SOnzV2Ap-?u*W3(Y`Ky;%g6lFS=U8xeXC-yYZ1!aY?R2V^AQ6ta!fRwh}O0DKd?4l3Z zCD)GUf{e`icqNZx*Qd@Y7a7jZy0Q}F5)J4rREygj4Mm7kfKyZSW{<069K?#VK{#?- z=EBNk*#RS5!=J7MBQg@zNEgb|eEkx0l>#~BN?5wXc#`BI;a0@eVN-+3TLRGxu9!V( zquvymp59}3GHzfhtRJ*REGw*`JCRmh znG`uJJCBva*B=H|K3N$>jwf8?Qqeo^z%fQ+v*$+5Q0zn%81j5LB*(+rA!E7P=WZ}v z{Ay&dk)}Grm>|l=Bz0lI_ROR zQdtKxDY9}`5ZsnhttM2)B1$obVwx`c)1$sq9`#+9?QrV56t>wF_Ge#FfO6i`dX{GzPao)U}+s&qN6o>EXi#w%7xJl7oq!o z6yUgaxTKG)=z3+2Cae2MdErQT@w7$H%9#>|&HXSOA43nr@zL~|a+iPzw@=WlOXF~d zz{XIXU#E*M<%?uQDk2N{ZeTHA%gw?KQ>g^2I!FRcV(c~LcsFl0R$D7g##YOn#E@H} dlX-^uLQA- literal 0 HcmV?d00001 diff --git a/docs/Providers/Group.md b/docs/Providers/Group.md new file mode 100644 index 0000000..f187b25 --- /dev/null +++ b/docs/Providers/Group.md @@ -0,0 +1,61 @@ +# Junos::Ez::Group::Provider + +Manages JUNOS group properties + +# EXAMPLE + +The provider *name* selector is the JUNOS group name, e.g. "service_group". + +```ruby +Junos::Ez::Group::Provider( ndev, :group ) + +grp = ndev.group["service_group"] + +grp[:format] = 'set' +grp[:path] = 'services.set' + +grp.write! + +``` + +# PROPERTIES + + - `:format` - JUNOS configuration format is file. It can be 'xml', 'text' or 'set'. Default is 'xml' + - `:path` - Path of configuration file that is applied inside JUNOS group hierarchy. + +# METHODS + +No additional methods at this time ... + +# USAGE NOTES + +Contents of 'service.set' file + +```` +% cat services.set +set system services ftp +set system services ssh +set system services netconf ssh +```` + +JUNOS group configuration reflected on executing above example. + +```` +{master}[edit] +junos@switch# show groups service_group +system { + services { + ftp; + ssh; + netconf { + ssh; + } + } +} + +junos@switch# show apply-groups +apply-groups [ global re0 re1 service_group ]; + +```` + + diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index b808f10..0fea230 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -8,8 +8,8 @@ Gem::Specification.new do |s| s.summary = "Junos EZ Framework - Standard Libraries" s.description = "Automation Framework for Junos/NETCONF: Facts, Providers, and Utils" s.homepage = 'https://github.com/Juniper/ruby-junos-ez-stdlib' - s.authors = ["Jeremy Schulman"] - s.email = 'jschulman@juniper.net' + s.authors = ["Jeremy Schulman", "John Deatherage", "Nitin Kumar, "Priyal Jain", "Ganesh Nalawade"] + s.email = 'jnpr-community-netdev@juniper.net' s.files = FileList[ '*', 'lib/**/*.rb', 'examples/**/*.rb', 'docs/**/*.md' ] s.add_dependency('netconf', ">= 0.2.5") end diff --git a/lib/junos-ez/group.rb b/lib/junos-ez/group.rb index 5389b53..b4cbb2b 100644 --- a/lib/junos-ez/group.rb +++ b/lib/junos-ez/group.rb @@ -137,7 +137,7 @@ def build_catalog return @catalog if list!.empty? list.each do |grp_name| @ndev.rpc.get_configuration{ |xml| - xml.gropus { + xml.groups { xml.name grp_name } }.xpath('groups').each do |as_xml| diff --git a/lib/junos-ez/version.rb b/lib/junos-ez/version.rb index 7baac3c..f82ca42 100644 --- a/lib/junos-ez/version.rb +++ b/lib/junos-ez/version.rb @@ -2,5 +2,5 @@ module Junos; end module Junos::Ez; end module Junos::Ez - VERSION = "0.2.0" + VERSION = "1.0.0" end From 177d33cf7a07044f7a9aed4a0b2718b22d4fae8e Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Fri, 11 Mar 2016 12:17:49 +0530 Subject: [PATCH 19/33] Remove swp file --- docs/Providers/.LAGports.md.swp | Bin 12288 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/Providers/.LAGports.md.swp diff --git a/docs/Providers/.LAGports.md.swp b/docs/Providers/.LAGports.md.swp deleted file mode 100644 index 896aedc727433e5d8832db75638dd7bcab17fc35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O>Z1E7{^_1ytG9iA;AHjZV*XIc6O715K}6;&?N*V%_=W#(JBz{jCa;$#$Js* zNjFs}Cpf`@0~b(xh67xI55ZReaRM%U00iRi*_R|J%ALw1{j!e7<9VK+UzBLwsb61S zrB{MQhU;<0O#9dCFDckU=fF?r82cXF2lv3|;4|1Z!1Lfa@GSV}QO5oTuYpTo0Xzeq27e*PKfxcs z<@+1(mp9-Icmv*mH{cC;1Kz-cYG4N!bLU5cy$Q4q z{^iOxD{s?fQnA<#Ql6N0g^N0FxPIJeRs0>=6SOnzV2Ap-?u*W3(Y`Ky;%g6lFS=U8xeXC-yYZ1!aY?R2V^AQ6ta!fRwh}O0DKd?4l3Z zCD)GUf{e`icqNZx*Qd@Y7a7jZy0Q}F5)J4rREygj4Mm7kfKyZSW{<069K?#VK{#?- z=EBNk*#RS5!=J7MBQg@zNEgb|eEkx0l>#~BN?5wXc#`BI;a0@eVN-+3TLRGxu9!V( zquvymp59}3GHzfhtRJ*REGw*`JCRmh znG`uJJCBva*B=H|K3N$>jwf8?Qqeo^z%fQ+v*$+5Q0zn%81j5LB*(+rA!E7P=WZ}v z{Ay&dk)}Grm>|l=Bz0lI_ROR zQdtKxDY9}`5ZsnhttM2)B1$obVwx`c)1$sq9`#+9?QrV56t>wF_Ge#FfO6i`dX{GzPao)U}+s&qN6o>EXi#w%7xJl7oq!o z6yUgaxTKG)=z3+2Cae2MdErQT@w7$H%9#>|&HXSOA43nr@zL~|a+iPzw@=WlOXF~d zz{XIXU#E*M<%?uQDk2N{ZeTHA%gw?KQ>g^2I!FRcV(c~LcsFl0R$D7g##YOn#E@H} dlX-^uLQA- From bccfc619e37da965da2ac121c4374e05a5feef86 Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Fri, 11 Mar 2016 13:17:48 +0530 Subject: [PATCH 20/33] Update junos-ez-stdlib.gemspec --- junos-ez-stdlib.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index 0fea230..8515eea 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -8,7 +8,7 @@ Gem::Specification.new do |s| s.summary = "Junos EZ Framework - Standard Libraries" s.description = "Automation Framework for Junos/NETCONF: Facts, Providers, and Utils" s.homepage = 'https://github.com/Juniper/ruby-junos-ez-stdlib' - s.authors = ["Jeremy Schulman", "John Deatherage", "Nitin Kumar, "Priyal Jain", "Ganesh Nalawade"] + s.authors = ["Jeremy Schulman", "John Deatherage", "Nitin Kumar", "Priyal Jain", "Ganesh Nalawade"] s.email = 'jnpr-community-netdev@juniper.net' s.files = FileList[ '*', 'lib/**/*.rb', 'examples/**/*.rb', 'docs/**/*.md' ] s.add_dependency('netconf', ">= 0.2.5") From e23437cf87d9a6bc4d96a2fa1d0280dd5f6888b3 Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Fri, 11 Mar 2016 13:18:39 +0530 Subject: [PATCH 21/33] Update to version 1.0.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eda435f..12288ee 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ documentation on Providers/Resources, see the *docs* directory. for any queries. Contributors: - [John Deatherage](https://github.com/routelastresort), [Nitin Kumar](https://github.com/vnitinv) + [John Deatherage](https://github.com/routelastresort), [Nitin Kumar](https://github.com/vnitinv), [Priyal Jain](https://github.com/jainpriyal), [Ganesh Nalawade](https://github.com/ganeshnalawade) Former Contributors: From 0d1ecb14cb5bfdd02ceebbe5888221f37e05eefd Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Fri, 11 Mar 2016 13:28:24 +0530 Subject: [PATCH 22/33] Update CHANGELOG.md --- CHANGELOG.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4ae35a..11b2990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,22 +69,23 @@ resources (LAGports) # 2016-March - - 1.0.0 - - Fixed issues - Issue #17: Add support for OCX device - Issue #20: "under development" error is thrown while importing the interface_create recipe from the Chef-Server. - Issue #22: "netdev_vlan" resource action delete is not working fine while invoking from the JUNOS Chef-Client. - Issue #23: RPC command error: commit-configuration is getting thrown on Invoking the "netdev_lag" resource from + + 1.0.0: + + Fixed issues + Issue #17 Add support for OCX device. + Issue #20 "under development" error is thrown while importing the interface_create recipe from the Chef-Server. + Issue #22 "netdev_vlan" resource action delete is not working fine while invoking from the JUNOS Chef-Client. + Issue #23 RPC command error: commit-configuration is getting thrown on Invoking the "netdev_lag" resource from JUNOS Chef Client. - Issue #27: Duplicate declaration of lag configuration in a recipe is giving NoMethodError: undefined method + Issue #27 Duplicate declaration of lag configuration in a recipe is giving NoMethodError: undefined method `properties' for nil:NilClass. - Issue #30: Error in rerunning netdev_lag interface. - Issue #33: undefined method `properties' for nil:NilClass error is thrown if the backup RE is unreachable. - Issue #35: Error in running chef client from Backup RE. - Issue #39: Getting 'Junos::Ez::NoProviderError' error on qfx device. - Issue #42: Raise exception to handle warnings in . + Issue #30 Error in rerunning netdev_lag interface. + Issue #33 undefined method `properties' for nil:NilClass error is thrown if the backup RE is unreachable. + Issue #35 Error in running chef client from Backup RE. + Issue #39 Getting 'Junos::Ez::NoProviderError' error on qfx device. + Issue #42 Raise exception to handle warnings in . - -Enhancement + Enhancement * Add support for configuring l2_interface on MX device. - * Add support for provider 'group' for configuring JUNOS groups. + * Add support for provider 'group' for configuring JUNOS groups. From 19db7e9015a7c6452476e879f2483778abf64bbf Mon Sep 17 00:00:00 2001 From: John Deatherage Date: Mon, 1 Aug 2016 22:42:24 -0700 Subject: [PATCH 23/33] required Gemspec lines, etc. - pushing 1.0.0 --- .gitignore | 1 + .rubocop.yml | 8 ++++++++ junos-ez-stdlib.gemspec | 11 ++++++----- lib/junos-ez/version.rb | 4 ++-- 4 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 .gitignore create mode 100644 .rubocop.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c111b33 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.gem diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..f921974 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,8 @@ +LineLength: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false + +Documentation: + Enabled: false diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index 8515eea..e5a264f 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -5,11 +5,12 @@ require 'junos-ez/version' Gem::Specification.new do |s| s.name = 'junos-ez-stdlib' s.version = Junos::Ez::VERSION - s.summary = "Junos EZ Framework - Standard Libraries" - s.description = "Automation Framework for Junos/NETCONF: Facts, Providers, and Utils" + s.summary = 'Junos EZ Framework - Standard Libraries' + s.description = 'Automation Framework for Junos/NETCONF: Facts, Providers, and Utils' s.homepage = 'https://github.com/Juniper/ruby-junos-ez-stdlib' - s.authors = ["Jeremy Schulman", "John Deatherage", "Nitin Kumar", "Priyal Jain", "Ganesh Nalawade"] + s.license = 'BSD-2-Clause' + s.authors = ['Jeremy Schulman', 'John Deatherage', 'Nitin Kumar', 'Priyal Jain', 'Ganesh Nalawade'] s.email = 'jnpr-community-netdev@juniper.net' - s.files = FileList[ '*', 'lib/**/*.rb', 'examples/**/*.rb', 'docs/**/*.md' ] - s.add_dependency('netconf', ">= 0.2.5") + s.files = FileList['*', 'lib/**/*.rb', 'examples/**/*.rb', 'docs/**/*.md'] + s.add_dependency('netconf', '>= 0.2.5') end diff --git a/lib/junos-ez/version.rb b/lib/junos-ez/version.rb index f82ca42..24d6c6b 100644 --- a/lib/junos-ez/version.rb +++ b/lib/junos-ez/version.rb @@ -1,6 +1,6 @@ module Junos; end module Junos::Ez; end - + module Junos::Ez - VERSION = "1.0.0" + VERSION = '1.0.0'.freeze end From 3c662413fc91cd6f005c0f49c4dc234301d5d78a Mon Sep 17 00:00:00 2001 From: John Deatherage Date: Mon, 1 Aug 2016 22:55:33 -0700 Subject: [PATCH 24/33] updated files metadata + version bump --- junos-ez-stdlib.gemspec | 4 ++-- lib/junos-ez/version.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index e5a264f..2fe83bc 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -11,6 +11,6 @@ Gem::Specification.new do |s| s.license = 'BSD-2-Clause' s.authors = ['Jeremy Schulman', 'John Deatherage', 'Nitin Kumar', 'Priyal Jain', 'Ganesh Nalawade'] s.email = 'jnpr-community-netdev@juniper.net' - s.files = FileList['*', 'lib/**/*.rb', 'examples/**/*.rb', 'docs/**/*.md'] - s.add_dependency('netconf', '>= 0.2.5') + s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + s.add_dependency('netconf', '~> 0.2.5') end diff --git a/lib/junos-ez/version.rb b/lib/junos-ez/version.rb index 24d6c6b..585b2f6 100644 --- a/lib/junos-ez/version.rb +++ b/lib/junos-ez/version.rb @@ -2,5 +2,5 @@ module Junos; end module Junos::Ez; end module Junos::Ez - VERSION = '1.0.0'.freeze + VERSION = '1.0.1'.freeze end From 234a380d5164784f0a4686cd923299fe6c69f99c Mon Sep 17 00:00:00 2001 From: John Deatherage Date: Mon, 1 Aug 2016 23:36:54 -0700 Subject: [PATCH 25/33] project metadata, test hooks, badges --- .gitignore | 11 +++++++ .rspec | 2 ++ .travis.yml | 18 +++++++++++ CHANGELOG.md | 53 ++++++++++++++++++------------- Gemfile | 7 +++++ README.md | 69 +++++++++++++++++++++-------------------- Rakefile | 6 ++++ junos-ez-stdlib.gemspec | 36 +++++++++++++-------- lib/junos-ez/version.rb | 2 +- spec/spec_helper.rb | 2 ++ 10 files changed, 138 insertions(+), 68 deletions(-) create mode 100644 .rspec create mode 100644 .travis.yml create mode 100644 Gemfile create mode 100644 Rakefile create mode 100644 spec/spec_helper.rb diff --git a/.gitignore b/.gitignore index c111b33..d15e998 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,12 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +.ruby-version *.gem +coverage diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..8c18f1a --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--format documentation +--color diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..60cd0f7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +sudo: false +language: ruby +rvm: + - 1.9.3-p551 + - 2.0.0-p648 + - 2.1.9 + - 2.2.5 + - 2.3.1 +matrix: + allow_failures: + - rvm: 1.9.3-p551 + - rvm: 2.0.0-p648 + fast_finish: true +before_install: gem update --remote bundler +install: + - bundle install --retry=3 +script: + - bundle exec rake build diff --git a/CHANGELOG.md b/CHANGELOG.md index 11b2990..23b2092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,70 +1,70 @@ # 2013-April 0.0.10: 2013-04-26 - + Initial release of code into RubyGems. Code tested on EX and SRX-branch. Consider this code as "early-adopter". Comments/feedback is welcome and appreciated. 0.0.11: 2013-04-26 - + Updated Junos::Ez::RE::Utils #memory changed :procs from Hash to Array #users changed return from Hash to Array - + 0.0.12: 2013-04-26 - + Updated Junos::Ez::FS:Utils#ls to include :symlink information Adding Junos::Ez::Users::Provider for login management Adding Junos::Ez::UserAuths::Provider for SSH-key management - + 0.0.14: 2013-04-28 - + Completed initial documentation. Still more work to be done with these files but the "enough to get started" information is now available - + # 2013-May 0.0.15: 2013-05-02 - + L2ports - added support for framework to read [edit vlans] stanza to recognize interfaces configured there vs. under [edit interfaces] - + IPports - added :acl_in and :acl_out for stateless ACL filtering. added .status method to return runtime status information about the port - + RE::Utils - misc updates, and documentation 0.0.16: 2013-05-03 - + RE::Utils - added support for license-key management. Renamed "software" methods from "xxx_software" to "software_xxx" to be consistent with other naming usage. Updated docs. - + 0.0.17: 2013-05-05 - + FS::Utils - updated docs. fixed methods so that all "error" scenarios raise IOError excaptions. - + 0.1.0: 2013-05-06 - + All docs and code _finished_ for the inital release of code. Always more to do, but at this point, declaring the framework "good for early adopter testing". Looking forward to bug-reports, please open issues against this repo. Thank you! - + 0.1.1: 2013-05-29 - + Fixed a small bug in fact gathering for hardwaremodel - + # 2013-July 0.1.2: 2013-07-04 - + Fixed issue#3. Previously this gem would not work with non-VC capable EX switches. Updated the `facts/version.rb` file to handle these devices. Also added a new fact `:vc_capable` that is set to `true` if the EX can support virtual-chassis, and `false` if it cannot. # 2013-Aug - 0.2.0: - + 0.2.0: + Fixed issue #6. Added support for EX4300 platform. Added new provider for Link Aggregation Group resources (LAGports) @@ -89,3 +89,14 @@ Enhancement * Add support for configuring l2_interface on MX device. * Add support for provider 'group' for configuring JUNOS groups. + +# 2016-August + + 1.0.2 + Fixed issues + Issue #46 Removing references to rake from gemspec + Issue #47 cannot get the git source code + + Enhancement + * Valid project metadata and rake for cleanly building/releasing + * Test hooks and badges diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..e7fe96b --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gemspec + +gem 'simplecov', require: false, group: :test diff --git a/README.md b/README.md index 12288ee..b9349ea 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ +[![Gem Version](https://badge.fury.io/rb/junos-ez-stdlib.svg)](https://badge.fury.io/rb/junos-ez-stdlib)[![Dependency Status](https://gemnasium.com/badges/github.com/Juniper/ruby-junos-ez-stdlib.svg)](https://gemnasium.com/github.com/Juniper/ruby-junos-ez-stdlib) +[![Build Status](https://travis-ci.org/Juniper/ruby-junos-ez-stdlib.svg?branch=master)](https://travis-ci.org/Juniper/ruby-junos-ez-stdlib) + # OVERVIEW Ruby framework to support Junos OS based device management automation. This is the "standard library" or "core" set of functionality that should work on most/all Junos OS based devices. -This framework is build on top of the NETCONF gem which uses XML as the fundamental data-exchange. So no -"automating the CLI" or using SNMP. The purpose of this framework is to **enable automation development +This framework is build on top of the NETCONF gem which uses XML as the fundamental data-exchange. So no +"automating the CLI" or using SNMP. The purpose of this framework is to **enable automation development without requiring specific Junos XML knowledge**. Further documentation can be found in the *docs* subdirectory. @@ -14,32 +17,32 @@ Further documentation can be found in the *docs* subdirectory. The framework is comprised of these basic eloements: - - Facts: + - Facts: A Hash of name/value pairs of information auto-collected. Fact values can be Hash structures as well so you can have deeply nested fact data. You can also define your own facts in addition to the "stdlib" facts. The facts are used by the framework to create a platform indepent layer of abstraction. This means that managing a VLAN, for example, is the same regardless of the underlying hardware platofrm (EX, QFX, MX, SRX, ...) - - - Resources: - Resources allow you to easily configure and perform operational functions on specific items within Junos, + - Resources: + + Resources allow you to easily configure and perform operational functions on specific items within Junos, for example VLANs, or switch ports. A resource has *properties* that you manipuate as Hash. You can - interact with Junos using resource methods like `read!`, `write!`, `delete!`, `activate!`, `deactivate!`, etc. + interact with Junos using resource methods like `read!`, `write!`, `delete!`, `activate!`, `deactivate!`, etc. For a complete listing of resource methods, refer to the *docs* directory - + - Providers: Providers allow you to manage a collection of resource, and most commonly, select a resource. The purpose of a provider/resource is to automate the life-cycle of common changes, like adding - VLANs, or ports to a VLAN. A provider also allows you to obtain a `list` of resources - (Array of *names*) or a `catalog` (Hash of resource properties). Providers may include resource - specific functionality, like using complex YAML/Hash data for easy import/export and provisioning + VLANs, or ports to a VLAN. A provider also allows you to obtain a `list` of resources + (Array of *names*) or a `catalog` (Hash of resource properties). Providers may include resource + specific functionality, like using complex YAML/Hash data for easy import/export and provisioning with Junos. If you need the ability to simply apply config-snippets that you do not need to model - as resources (as you might for initial device commissioning), the Utilities library is where you + as resources (as you might for initial device commissioning), the Utilities library is where you want to start. - + - Utilities: Utilities are simply collections of functions. The **configuration** utilities, for example, will @@ -47,9 +50,9 @@ The framework is comprised of these basic eloements: for unmanaged provider/resources (like initial configuration of the device). The **routing-engine** utilities, for example, will allow you to easily upgrade software, check memory usage, and do `ping` operations. - + # EXAMPLE USAGE - + ```ruby require 'pp' require 'net/netconf/jnpr' @@ -60,7 +63,7 @@ unless ARGV[0] exit 1 end -# login information for NETCONF session +# login information for NETCONF session login = { :target => ARGV[0], :username => 'jeremy', :password => 'jeremy1', } ## create a NETCONF object to manage the device and open the connection ... @@ -71,8 +74,8 @@ ndev.open puts "OK!" ## Now bind providers to the device object. The 'Junos::Ez::Provider' must be first. -## This will retrieve the device 'facts'. The other providers allow you to define the -## provider variables; so this example is using 'l1_ports' and 'ip_ports', but you could name +## This will retrieve the device 'facts'. The other providers allow you to define the +## provider variables; so this example is using 'l1_ports' and 'ip_ports', but you could name ## them what you like, yo! Junos::Ez::Provider( ndev ) @@ -125,7 +128,7 @@ ndev.cu.rollback! ndev.close ``` - + # PROVIDERS Providers manage access to individual resources and their associated properties. Providers/resources exists @@ -137,30 +140,30 @@ documentation on Providers/Resources, see the *docs* directory. - Vlans: VLAN resource management - IPports: IP v4 port management - StaticHosts: Static Hosts [system static-host-mapping ...] - - StaticRoutes: Static Routes [routing-options static ...] - - Group: JUNOS groups management + - StaticRoutes: Static Routes [routing-options static ...] + - Group: JUNOS groups management # UTILITIES - Config: - + These functions allow you to load config snippets, do commit checks, look at config diffs, etc. - Generally speaking, you would want to use the Providers/Resources framework to manage specific + Generally speaking, you would want to use the Providers/Resources framework to manage specific items in the config. This utility library is very useful when doing the initial commissioning process, where you do not (cannot) model every aspect of Junos. These utilities can also be used in conjunction with Providers/Resources, specifically around locking/unlocking and committing the configuration. - + - Filesystem: - + These functions provide you "unix-like" commands that return data in Hash forms rather than as string output you'd normally have to screen-scraps. These methods include `ls`, `df`, `pwd`, `cwd`, `cleanup`, and `cleanup!` - Routing-Engine: - - These functions provide a general collection to information and functioanlity for handling - routing-engine (RE) processes. These functions `reboot!`, `shutdown!`, `install_software!`, + + These functions provide a general collection to information and functioanlity for handling + routing-engine (RE) processes. These functions `reboot!`, `shutdown!`, `install_software!`, `ping`. Information gathering such as memory-usage, current users, and RE status information is also made available through this collection. @@ -168,19 +171,19 @@ documentation on Providers/Resources, see the *docs* directory. * gem netconf * Junos OS based products - -# INSTALLATION + +# INSTALLATION * gem install junos-ez-stdlib # CONTRIBUTORS - Juniper Networks is actively contributing to and maintaining this repo. Please contact jnpr-community-netdev@juniper.net + Juniper Networks is actively contributing to and maintaining this repo. Please contact jnpr-community-netdev@juniper.net for any queries. - + Contributors: [John Deatherage](https://github.com/routelastresort), [Nitin Kumar](https://github.com/vnitinv), [Priyal Jain](https://github.com/jainpriyal), [Ganesh Nalawade](https://github.com/ganeshnalawade) - + Former Contributors: [Jeremy Schulman](https://github.com/jeremyschulman) diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..4c774a2 --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) + +task default: :spec diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index 2fe83bc..26efc16 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -1,16 +1,26 @@ -$LOAD_PATH.unshift 'lib' -require 'rake' +# frozen_string_literal: true +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'junos-ez/version' -Gem::Specification.new do |s| - s.name = 'junos-ez-stdlib' - s.version = Junos::Ez::VERSION - s.summary = 'Junos EZ Framework - Standard Libraries' - s.description = 'Automation Framework for Junos/NETCONF: Facts, Providers, and Utils' - s.homepage = 'https://github.com/Juniper/ruby-junos-ez-stdlib' - s.license = 'BSD-2-Clause' - s.authors = ['Jeremy Schulman', 'John Deatherage', 'Nitin Kumar', 'Priyal Jain', 'Ganesh Nalawade'] - s.email = 'jnpr-community-netdev@juniper.net' - s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - s.add_dependency('netconf', '~> 0.2.5') +Gem::Specification.new do |spec| + spec.name = 'junos-ez-stdlib' + spec.version = Junos::Ez::VERSION + spec.authors = ['Jeremy Schulman', 'John Deatherage', 'Nitin Kumar', 'Priyal Jain', 'Ganesh Nalawade'] + spec.email = 'jnpr-community-netdev@juniper.net' + + spec.summary = 'Junos EZ Framework - Standard Libraries' + spec.description = 'Automation Framework for Junos/NETCONF: Facts, Providers, and Utils' + spec.homepage = 'https://github.com/Juniper/ruby-junos-ez-stdlib' + spec.license = 'BSD-2-Clause' + + spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + + spec.add_dependency('netconf', '~> 0.2.5') + + spec.add_development_dependency 'bundler', '~> 1.12' + spec.add_development_dependency 'rake', '~> 10.0' + spec.add_development_dependency 'rspec', '~> 3.0' + spec.add_development_dependency 'rubocop', '~> 0.42.0' end diff --git a/lib/junos-ez/version.rb b/lib/junos-ez/version.rb index 585b2f6..afc6c71 100644 --- a/lib/junos-ez/version.rb +++ b/lib/junos-ez/version.rb @@ -2,5 +2,5 @@ module Junos; end module Junos::Ez; end module Junos::Ez - VERSION = '1.0.1'.freeze + VERSION = '1.0.2'.freeze end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..39e075f --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,2 @@ +require 'simplecov' +SimpleCov.start From c44edc2a60cc90305cd3db49c57cada45626ba4b Mon Sep 17 00:00:00 2001 From: John Deatherage Date: Mon, 1 Aug 2016 23:57:19 -0700 Subject: [PATCH 26/33] pessimistic version bump --- CHANGELOG.md | 3 ++- junos-ez-stdlib.gemspec | 2 +- lib/junos-ez/version.rb | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23b2092..17d3423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,7 +92,7 @@ # 2016-August - 1.0.2 + 1.0.3 Fixed issues Issue #46 Removing references to rake from gemspec Issue #47 cannot get the git source code @@ -100,3 +100,4 @@ Enhancement * Valid project metadata and rake for cleanly building/releasing * Test hooks and badges + * netconf gem pessimistic version constraint to 0.3.1 diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index 26efc16..97760ac 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |spec| spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - spec.add_dependency('netconf', '~> 0.2.5') + spec.add_dependency('netconf', '~> 0.3.1') spec.add_development_dependency 'bundler', '~> 1.12' spec.add_development_dependency 'rake', '~> 10.0' diff --git a/lib/junos-ez/version.rb b/lib/junos-ez/version.rb index afc6c71..a9b1b95 100644 --- a/lib/junos-ez/version.rb +++ b/lib/junos-ez/version.rb @@ -2,5 +2,5 @@ module Junos; end module Junos::Ez; end module Junos::Ez - VERSION = '1.0.2'.freeze + VERSION = '1.0.3'.freeze end From 634aff8152f084b220f6746e1b195c46abdfa54a Mon Sep 17 00:00:00 2001 From: "Ganesh B. Nalawade" Date: Thu, 20 Apr 2017 13:44:45 +0530 Subject: [PATCH 27/33] Change GitHub handle --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b9349ea..133a020 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ documentation on Providers/Resources, see the *docs* directory. Contributors: [John Deatherage](https://github.com/routelastresort), [Nitin Kumar](https://github.com/vnitinv), - [Priyal Jain](https://github.com/jainpriyal), [Ganesh Nalawade](https://github.com/ganeshnalawade) + [Priyal Jain](https://github.com/jainpriyal), [Ganesh Nalawade](https://github.com/ganeshrn) Former Contributors: [Jeremy Schulman](https://github.com/jeremyschulman) From 7e7e9547417718504ec496c9147fa71ee8dd1916 Mon Sep 17 00:00:00 2001 From: Lucas Perez Date: Tue, 3 Apr 2018 08:32:15 -0300 Subject: [PATCH 28/33] Fix diff? method for newer JunOS versions --- lib/junos-ez/utils/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/junos-ez/utils/config.rb b/lib/junos-ez/utils/config.rb index 5f2148b..c3cda08 100644 --- a/lib/junos-ez/utils/config.rb +++ b/lib/junos-ez/utils/config.rb @@ -169,7 +169,7 @@ def rollback!( rollback_id = 0 ) def diff?( rollback_id = 0 ) raise ArgumentError, "invalid rollback #{rollback_id}" unless ( rollback_id >= 0 and rollback_id <= 50 ) - got = ndev.rpc.get_configuration( :compare=>'rollback', :rollback=> rollback_id.to_s ) + got = ndev.rpc.get_configuration( :compare => 'rollback', :rollback => rollback_id.to_s, :format => 'text' ) diff = got.xpath('configuration-output').text return nil if diff == "\n" diff From 4244f4f05d3605e350ae7480f162397496d38698 Mon Sep 17 00:00:00 2001 From: Nitin Kr Date: Fri, 13 Apr 2018 15:08:13 +0530 Subject: [PATCH 29/33] fix security vulnerability fix below warning from github ``` We found a potential security vulnerability in one of your dependencies. A dependency defined in ./junos-ez-stdlib.gemspec has known security vulnerabilities and should be updated. ``` --- junos-ez-stdlib.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index 97760ac..1cac940 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -22,5 +22,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 1.12' spec.add_development_dependency 'rake', '~> 10.0' spec.add_development_dependency 'rspec', '~> 3.0' - spec.add_development_dependency 'rubocop', '~> 0.42.0' + spec.add_development_dependency 'rubocop', '~> 0.49.0' end From 19f92e2a23884bbab51dc21b17695a8c880cbae6 Mon Sep 17 00:00:00 2001 From: mahantesh Date: Mon, 8 Oct 2018 14:01:41 +0530 Subject: [PATCH 30/33] Added PTX product model. --- lib/junos-ez/facts/personality.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/junos-ez/facts/personality.rb b/lib/junos-ez/facts/personality.rb index 4d8c35d..120b70b 100644 --- a/lib/junos-ez/facts/personality.rb +++ b/lib/junos-ez/facts/personality.rb @@ -6,7 +6,7 @@ examine = ( model != "Virtual Chassis" ) ? model : facts.select {|k,v| k.match(/^RE[0..9]+/) }.values[0][:model] facts[:personality] = case examine - when /^(EX)|(QFX)|(OCX)/i + when /^(EX)|(QFX)|(PTX)|(OCX)/i :SWITCH when /^MX/i :MX From 834a9ae41c8fbd34af1c571bb0c37d1407430e33 Mon Sep 17 00:00:00 2001 From: mahantesh Date: Sun, 23 Dec 2018 10:05:18 +0530 Subject: [PATCH 31/33] Normally, REs are expected to be named as RE0 or RE1. But on some versions of QFX, REs are named as LOCALRE. This code patch accommodates this deviation in naming convention and returns the version number of LOCALRE. --- lib/junos-ez/facts/version.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/junos-ez/facts/version.rb b/lib/junos-ez/facts/version.rb index d4fc740..a3630d1 100644 --- a/lib/junos-ez/facts/version.rb +++ b/lib/junos-ez/facts/version.rb @@ -43,6 +43,7 @@ unless master_id.nil? facts[:version] = facts[("version_" + "RE" + master_id).to_sym] || + facts[("version_" + "LOCALRE").to_sym] || facts[('version_' + "FPC" + master_id).to_sym] end else From 024230275c8007d1281cb96eee8223bc7012162e Mon Sep 17 00:00:00 2001 From: Jake Bell Date: Thu, 17 Mar 2016 12:09:37 -0500 Subject: [PATCH 32/33] Removing references to rake from gemspec --- junos-ez-stdlib.gemspec | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/junos-ez-stdlib.gemspec b/junos-ez-stdlib.gemspec index 1cac940..3c1a5a0 100644 --- a/junos-ez-stdlib.gemspec +++ b/junos-ez-stdlib.gemspec @@ -1,26 +1,14 @@ -# frozen_string_literal: true -# coding: utf-8 -lib = File.expand_path('../lib', __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +$LOAD_PATH.unshift 'lib' require 'junos-ez/version' -Gem::Specification.new do |spec| - spec.name = 'junos-ez-stdlib' - spec.version = Junos::Ez::VERSION - spec.authors = ['Jeremy Schulman', 'John Deatherage', 'Nitin Kumar', 'Priyal Jain', 'Ganesh Nalawade'] - spec.email = 'jnpr-community-netdev@juniper.net' - - spec.summary = 'Junos EZ Framework - Standard Libraries' - spec.description = 'Automation Framework for Junos/NETCONF: Facts, Providers, and Utils' - spec.homepage = 'https://github.com/Juniper/ruby-junos-ez-stdlib' - spec.license = 'BSD-2-Clause' - - spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - - spec.add_dependency('netconf', '~> 0.3.1') - - spec.add_development_dependency 'bundler', '~> 1.12' - spec.add_development_dependency 'rake', '~> 10.0' - spec.add_development_dependency 'rspec', '~> 3.0' - spec.add_development_dependency 'rubocop', '~> 0.49.0' +Gem::Specification.new do |s| + s.name = 'junos-ez-stdlib' + s.version = Junos::Ez::VERSION + s.summary = "Junos EZ Framework - Standard Libraries" + s.description = "Automation Framework for Junos/NETCONF: Facts, Providers, and Utils" + s.homepage = 'https://github.com/Juniper/ruby-junos-ez-stdlib' + s.authors = ["Jeremy Schulman"] + s.email = 'jschulman@juniper.net' + s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + s.add_dependency('netconf', ">= 0.2.5") end From 31b76933537163c346378b7982f032d2ec36d917 Mon Sep 17 00:00:00 2001 From: Lucas Perez Date: Tue, 3 Apr 2018 11:32:24 -0300 Subject: [PATCH 33/33] Fix diff? method for newer JunOS versions --- Gemfile.lock | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..5f25f6c --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,69 @@ +PATH + remote: . + specs: + junos-ez-stdlib (1.0.3) + netconf (~> 0.3.1) + +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.0) + diff-lcs (1.3) + docile (1.3.0) + json (2.1.0) + mini_portile2 (2.3.0) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (4.2.0) + netconf (0.3.1) + net-scp + net-ssh (>= 2.5.2) + nokogiri (>= 1.5.5) + nokogiri (1.8.2) + mini_portile2 (~> 2.3.0) + parser (2.5.0.5) + ast (~> 2.4.0) + powerpack (0.1.1) + rainbow (2.2.2) + rake + rake (10.5.0) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-mocks (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.1) + rubocop (0.42.0) + parser (>= 2.3.1.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + ruby-progressbar (1.9.0) + simplecov (0.16.1) + docile (~> 1.1) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + unicode-display_width (1.3.0) + +PLATFORMS + ruby + +DEPENDENCIES + bundler (~> 1.12) + junos-ez-stdlib! + rake (~> 10.0) + rspec (~> 3.0) + rubocop (~> 0.42.0) + simplecov + +BUNDLED WITH + 1.16.1