Skip to content

Instantly share code, notes, and snippets.

@peelman
Last active April 14, 2025 02:08
Show Gist options
  • Save peelman/d6569a0691c7118ffc762010e918d554 to your computer and use it in GitHub Desktop.
Save peelman/d6569a0691c7118ffc762010e918d554 to your computer and use it in GitHub Desktop.

Revisions

  1. peelman revised this gist Apr 14, 2025. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # SFP Change Trap Handler
    # Nokia SFP Change Trap Handler

    Posted mostly for inspiration.

    @@ -17,10 +17,10 @@ Posted mostly for inspiration.
    [TrapFiles]
    # A list of snmptt.conf files (this is NOT the snmptrapd.conf file). The COMPLETE path
    # and filename. Ex: '/etc/snmp/snmptt.conf'
    # /etc/snmp/traps.d/ietf-ifmib.conf
    # /etc/snmp/traps.d/nokia-traps.conf
    #
    snmptt_conf_files = <<END
    /etc/snmp/traps.d/ietf-ifmib.conf
    /etc/snmp/traps.d/nokia-traps.conf
    END
    ```

  2. peelman revised this gist Apr 14, 2025. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -51,4 +51,5 @@ EDESC

    ## Sample output


    ![image](https://gist.github.com/user-attachments/assets/3fbbf05f-43a5-4786-945d-09c42f4e19b3)
    ![image](https://gist.github.com/user-attachments/assets/cadd9552-7415-4e36-8f33-cf3355b028c3)
  3. peelman created this gist Apr 14, 2025.
    54 changes: 54 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,54 @@
    # SFP Change Trap Handler

    Posted mostly for inspiration.

    ## Installation

    1. Copy `nokia_sfp_changed.rb` to `/usr/local/bin` (or wherever you store scripts on your system(s).
    2. Be sure the following Gems are installed: `optparse`, `slack-notifier`, `snmp`


    ## Configuration

    ### SNMPtt

    `/etc/snmp/snmptt.ini` (Debian/Ubuntu Location, YMMV)
    ```
    [TrapFiles]
    # A list of snmptt.conf files (this is NOT the snmptrapd.conf file). The COMPLETE path
    # and filename. Ex: '/etc/snmp/snmptt.conf'
    # /etc/snmp/traps.d/ietf-ifmib.conf
    #
    snmptt_conf_files = <<END
    /etc/snmp/traps.d/ietf-ifmib.conf
    END
    ```

    `/etc/snmp/traps.d/nokia-traps.conf`
    ```
    ...
    EVENT tmnxEqPortSFPInserted .1.3.6.1.4.1.6527.3.1.3.2.2.0.8 "Status Events" Normal
    FORMAT Generated when an SFF is inserted in the port. $*
    EXEC /usr/local/bin/nokia_sfp_changed.rb -h $A -c <yourcommunitystring> -p $1 -i
    SDESC
    Generated when an SFF is inserted in the port.
    Variables:
    1: tmnxPortNotifyPortId
    EDESC
    #
    #
    #
    EVENT tmnxEqPortSFPRemoved .1.3.6.1.4.1.6527.3.1.3.2.2.0.9 "Status Events" Normal
    FORMAT Generated when an SFF is removed from the port. $*
    EXEC /usr/local/bin/nokia_sfp_changed.rb -h $A -c <yourcommunitystring> -p $1 -r
    SDESC
    Generated when an SFF is removed from the port.
    Variables:
    1: tmnxPortNotifyPortId
    EDESC
    ...
    ```

    ## Sample output


    176 changes: 176 additions & 0 deletions nokia_sfp_changed.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,176 @@
    #!/usr/bin/env ruby
    ######################################################################################################
    #
    # Description:
    # Handle SNMP Traps for Nokia SFP Changes
    # * Post All Traps to Slack Channel provided by SLACK_WEBHOOK_URL
    #
    ######################################################################################################
    #
    # Author: Nick Peelman
    #
    ######################################################################################################
    #
    # Usage:
    # nokia_sfp_changed.rb -h <hostname> -c <community> -p <index> [-i|-r]"
    # Parameters:
    # * <hostname>: Hostname that sent the trap
    # * <community>: SNMP Community with Read privileges to the IF-MIB
    # * <index>: the index of the interface that send the event
    #
    ######################################################################################################
    #
    # Requirements
    # * gem install slack-notifier
    # * gem install snmp
    #
    ######################################################################################################

    require 'optparse'
    require 'slack-notifier'
    require 'snmp'
    ######################################################################################################
    # CONFIGURATION Parameters
    #
    SLACK_WEBHOOK_URL = ""
    SLACK_CHANNEL = "#port-notifications"

    ######################################################################################################

    @oid_sysname = SNMP::ObjectName.new "1.3.6.1.2.1.1.5.0"
    @oid_port_id_schema = SNMP::ObjectName.new "1.3.6.1.4.1.6527.3.1.2.2.1.3.1.32.1"
    @oid_sfp_type = SNMP::ObjectName.new "1.3.6.1.4.1.6527.3.1.2.2.4.2.1.46.1"
    @oid_ifname = SNMP::ObjectName.new "1.3.6.1.2.1.31.1.1.1.1"

    @oid_array = [
    @oid_sysname,
    @oid_port_id_schema,
    @oid_sfp_type,
    @oid_ifname
    ]

    @sysname = ''
    @port_scheme = 0
    @sfp_type = ''
    @ifname = ''

    def parse_args(args = {})
    @print = args[:print].nil? ? true : args[:print]
    @exit = args[:exit].nil? ? true : args[:exit]

    # now, handle the arguments...
    @opts = OptionParser.new
    @opts.on("-h", "--hostname HOSTNAME", "Hostname") do |h|
    @hostname = h
    end
    @opts.on("-c", "--community COMMUNITY", "snmp community") do |c|
    @community = c
    end
    @opts.on("-p", "--port PORTID", "Port ID") do |p|
    @port_id = p
    end
    @opts.on("-r", "--removed", "SFP Removed") do |r|
    @removed = true
    end
    @opts.on("-i", "--inserted", "SFP Inserted") do |i|
    @inserted = true
    end
    @opts.on("-d", "--debug", "print output, don't send to slack") do |d|
    @debug = true
    end
    @opts.on_tail("-h", "--help", "Show this message") do
    puts @opts
    exit
    end
    @opts.parse!
    end

    def bin_to_int(array)
    array.join('').to_i(2)
    end

    def safe_vb_to_int(number, safe = 0)
    Integer(number) rescue safe
    end

    def fetch_oids(host, community)
    SNMP::Manager.open(host: host, community: community) do |manager|
    response = manager.get(@oid_array)
    response.each_varbind do |vb|
    case vb.name.to_str
    when @oid_sysname.to_str
    @sysname = vb.value
    when @oid_port_id_schema.to_str
    @port_scheme = safe_vb_to_int(vb.value)
    when @oid_sfp_type.to_str
    @sfp_type = vb.value
    when @oid_ifname.to_str
    @ifname = vb.value
    else
    puts "Error: unknown VarBind returned: #{vb}"
    end
    end
    end
    end

    def send_slack_message(message, attachments)
    notifier = Slack::Notifier.new SLACK_WEBHOOK_URL
    notifier.post({text:"#{message}", attachments: attachments})
    end

    def main
    parse_args

    @oid_sfp_type.push(@port_id)
    @oid_ifname.push(@port_id)

    fetch_oids(@hostname, @community)

    @msgcolor = "#cccccc"
    @emoji = ':black_square_button:'

    if @inserted
    @state = "Inserted"
    @msgcolor = 'good'
    @emoji = ":large_green_circle:"
    elsif @removed
    @state = "Removed"
    @msgcolor = 'warning'
    @emoji = ":large_yellow_circle:"
    else
    @state = "Unknown"
    end

    message = "#{@emoji} SFP Changed: #{@hostname} - Port: #{@ifname} - #{@state}"
    attachments = [{
    'color': "#{@msgcolor}",
    'fallback': message,
    'fields': [
    {
    'title': "Device",
    'value': "#{@hostname}",
    'short': true
    },
    {
    'title': "Port",
    'value': "#{@ifname}",
    'short': true
    },
    {
    'title': "SFP",
    'value': "#{@state}",
    'short': true
    },
    {
    'title': "SFP Type",
    'value': "#{@sfp_type}",
    'short': true
    }

    ]
    }]
    puts attachments if @debug
    send_slack_message('', attachments) unless @debug
    end

    main