telemetry-snmp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rspec.yml +44 -0
  3. data/.github/workflows/rubocop.yml +28 -0
  4. data/.github/workflows/sourcehawk-scan.yml +20 -0
  5. data/.gitignore +14 -0
  6. data/.rspec +4 -0
  7. data/.rubocop.yml +26 -0
  8. data/CHANGELOG.md +4 -0
  9. data/CODE_OF_CONDUCT.md +75 -0
  10. data/CONTRIBUTING.md +54 -0
  11. data/Gemfile +10 -0
  12. data/INDIVIDUAL_CONTRIBUTOR_LICENSE.md +30 -0
  13. data/LICENSE +201 -0
  14. data/NOTICE.txt +9 -0
  15. data/README.md +54 -0
  16. data/attribution.txt +1 -0
  17. data/config.ru +15 -0
  18. data/exe/snmp_collector +55 -0
  19. data/lib/telemetry/snmp.rb +23 -0
  20. data/lib/telemetry/snmp/api.rb +55 -0
  21. data/lib/telemetry/snmp/auth.rb +54 -0
  22. data/lib/telemetry/snmp/auth/defaults.rb +41 -0
  23. data/lib/telemetry/snmp/client.rb +104 -0
  24. data/lib/telemetry/snmp/controllers/device_creds.rb +105 -0
  25. data/lib/telemetry/snmp/controllers/devices.rb +94 -0
  26. data/lib/telemetry/snmp/controllers/oid_groups.rb +71 -0
  27. data/lib/telemetry/snmp/controllers/oids.rb +80 -0
  28. data/lib/telemetry/snmp/controllers/users.rb +81 -0
  29. data/lib/telemetry/snmp/controllers/walks.rb +89 -0
  30. data/lib/telemetry/snmp/data.rb +69 -0
  31. data/lib/telemetry/snmp/data/default_opts.rb +73 -0
  32. data/lib/telemetry/snmp/data/migrations/001_device_creds.rb +19 -0
  33. data/lib/telemetry/snmp/data/migrations/002_create_devices_table.rb +31 -0
  34. data/lib/telemetry/snmp/data/migrations/003_create_oids_tables.rb +16 -0
  35. data/lib/telemetry/snmp/data/migrations/004_create_oid_groups.rb +15 -0
  36. data/lib/telemetry/snmp/data/migrations/005_create_oids_oid_groups.rb +17 -0
  37. data/lib/telemetry/snmp/data/migrations/006_device_to_oid_group.rb +15 -0
  38. data/lib/telemetry/snmp/data/migrations/007_create_users.rb +20 -0
  39. data/lib/telemetry/snmp/data/migrations/008_create_walks_table.rb +14 -0
  40. data/lib/telemetry/snmp/data/migrations/009_create_tag_name_column.rb +7 -0
  41. data/lib/telemetry/snmp/data/migrations/010_create_user_audit_table.rb +18 -0
  42. data/lib/telemetry/snmp/data/models/device.rb +11 -0
  43. data/lib/telemetry/snmp/data/models/device_cred.rb +11 -0
  44. data/lib/telemetry/snmp/data/models/oid.rb +10 -0
  45. data/lib/telemetry/snmp/data/models/oid_group.rb +10 -0
  46. data/lib/telemetry/snmp/data/models/oid_oid_groups.rb +10 -0
  47. data/lib/telemetry/snmp/data/models/oid_walk.rb +10 -0
  48. data/lib/telemetry/snmp/data/models/user.rb +10 -0
  49. data/lib/telemetry/snmp/data/models/user_audit_log.rb +19 -0
  50. data/lib/telemetry/snmp/mibs/AGENTX-MIB.txt +527 -0
  51. data/lib/telemetry/snmp/mibs/AIRPORT-BASESTATION-3-MIB.txt +461 -0
  52. data/lib/telemetry/snmp/mibs/BRIDGE-MIB.txt +1472 -0
  53. data/lib/telemetry/snmp/mibs/DISMAN-EVENT-MIB.txt +1882 -0
  54. data/lib/telemetry/snmp/mibs/DISMAN-SCHEDULE-MIB.txt +699 -0
  55. data/lib/telemetry/snmp/mibs/DISMAN-SCRIPT-MIB.txt +1764 -0
  56. data/lib/telemetry/snmp/mibs/EtherLike-MIB.txt +1862 -0
  57. data/lib/telemetry/snmp/mibs/HCNUM-TC.txt +118 -0
  58. data/lib/telemetry/snmp/mibs/HOST-RESOURCES-MIB.txt +1540 -0
  59. data/lib/telemetry/snmp/mibs/HOST-RESOURCES-TYPES.txt +389 -0
  60. data/lib/telemetry/snmp/mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB.txt +123 -0
  61. data/lib/telemetry/snmp/mibs/IANA-LANGUAGE-MIB.txt +123 -0
  62. data/lib/telemetry/snmp/mibs/IANA-RTPROTO-MIB.txt +91 -0
  63. data/lib/telemetry/snmp/mibs/IANAifType-MIB.txt +619 -0
  64. data/lib/telemetry/snmp/mibs/IF-INVERTED-STACK-MIB.txt +149 -0
  65. data/lib/telemetry/snmp/mibs/IF-MIB.txt +1814 -0
  66. data/lib/telemetry/snmp/mibs/INET-ADDRESS-MIB.txt +402 -0
  67. data/lib/telemetry/snmp/mibs/IP-FORWARD-MIB.txt +1277 -0
  68. data/lib/telemetry/snmp/mibs/IP-MIB.txt +4993 -0
  69. data/lib/telemetry/snmp/mibs/IPV6-FLOW-LABEL-MIB.txt +58 -0
  70. data/lib/telemetry/snmp/mibs/IPV6-ICMP-MIB.txt +529 -0
  71. data/lib/telemetry/snmp/mibs/IPV6-MIB.txt +1443 -0
  72. data/lib/telemetry/snmp/mibs/IPV6-TC.txt +67 -0
  73. data/lib/telemetry/snmp/mibs/IPV6-TCP-MIB.txt +211 -0
  74. data/lib/telemetry/snmp/mibs/IPV6-UDP-MIB.txt +141 -0
  75. data/lib/telemetry/snmp/mibs/NET-SNMP-AGENT-MIB.txt +554 -0
  76. data/lib/telemetry/snmp/mibs/NET-SNMP-EXAMPLES-MIB.txt +285 -0
  77. data/lib/telemetry/snmp/mibs/NET-SNMP-EXTEND-MIB.txt +325 -0
  78. data/lib/telemetry/snmp/mibs/NET-SNMP-MIB.txt +67 -0
  79. data/lib/telemetry/snmp/mibs/NET-SNMP-PASS-MIB.txt +124 -0
  80. data/lib/telemetry/snmp/mibs/NET-SNMP-TC.txt +128 -0
  81. data/lib/telemetry/snmp/mibs/NET-SNMP-VACM-MIB.txt +154 -0
  82. data/lib/telemetry/snmp/mibs/NOTIFICATION-LOG-MIB.txt +753 -0
  83. data/lib/telemetry/snmp/mibs/PAN-COMMON-MIB.md5 +1 -0
  84. data/lib/telemetry/snmp/mibs/PAN-COMMON-MIB.my +2293 -0
  85. data/lib/telemetry/snmp/mibs/PAN-ENTITY-EXT-MIB.md5 +1 -0
  86. data/lib/telemetry/snmp/mibs/PAN-ENTITY-EXT-MIB.my +293 -0
  87. data/lib/telemetry/snmp/mibs/PAN-GLOBAL-REG-MIB.md5 +1 -0
  88. data/lib/telemetry/snmp/mibs/PAN-GLOBAL-REG-MIB.my +84 -0
  89. data/lib/telemetry/snmp/mibs/PAN-GLOBAL-TC-MIB.md5 +1 -0
  90. data/lib/telemetry/snmp/mibs/PAN-GLOBAL-TC-MIB.my +68 -0
  91. data/lib/telemetry/snmp/mibs/PAN-LC-MIB.md5 +1 -0
  92. data/lib/telemetry/snmp/mibs/PAN-LC-MIB.my +204 -0
  93. data/lib/telemetry/snmp/mibs/PAN-PRODUCT-MIB.md5 +1 -0
  94. data/lib/telemetry/snmp/mibs/PAN-PRODUCT-MIB.my +305 -0
  95. data/lib/telemetry/snmp/mibs/PAN-TRAPS.md5 +1 -0
  96. data/lib/telemetry/snmp/mibs/PAN-TRAPS.my +7809 -0
  97. data/lib/telemetry/snmp/mibs/RFC-1215.txt +38 -0
  98. data/lib/telemetry/snmp/mibs/RFC1155-SMI.txt +119 -0
  99. data/lib/telemetry/snmp/mibs/RFC1213-MIB.txt +2613 -0
  100. data/lib/telemetry/snmp/mibs/RMON-MIB.txt +3980 -0
  101. data/lib/telemetry/snmp/mibs/SCTP-MIB.txt +1342 -0
  102. data/lib/telemetry/snmp/mibs/SMUX-MIB.txt +160 -0
  103. data/lib/telemetry/snmp/mibs/SNMP-COMMUNITY-MIB.txt +429 -0
  104. data/lib/telemetry/snmp/mibs/SNMP-FRAMEWORK-MIB.txt +526 -0
  105. data/lib/telemetry/snmp/mibs/SNMP-MPD-MIB.txt +145 -0
  106. data/lib/telemetry/snmp/mibs/SNMP-NOTIFICATION-MIB.txt +589 -0
  107. data/lib/telemetry/snmp/mibs/SNMP-PROXY-MIB.txt +294 -0
  108. data/lib/telemetry/snmp/mibs/SNMP-TARGET-MIB.txt +660 -0
  109. data/lib/telemetry/snmp/mibs/SNMP-USER-BASED-SM-MIB.txt +912 -0
  110. data/lib/telemetry/snmp/mibs/SNMP-USM-AES-MIB.txt +62 -0
  111. data/lib/telemetry/snmp/mibs/SNMP-USM-DH-OBJECTS-MIB.txt +532 -0
  112. data/lib/telemetry/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.txt +830 -0
  113. data/lib/telemetry/snmp/mibs/SNMPv2-CONF.txt +322 -0
  114. data/lib/telemetry/snmp/mibs/SNMPv2-MIB.txt +854 -0
  115. data/lib/telemetry/snmp/mibs/SNMPv2-SMI.txt +344 -0
  116. data/lib/telemetry/snmp/mibs/SNMPv2-TC.txt +772 -0
  117. data/lib/telemetry/snmp/mibs/SNMPv2-TM.txt +176 -0
  118. data/lib/telemetry/snmp/mibs/TCP-MIB.txt +785 -0
  119. data/lib/telemetry/snmp/mibs/TRANSPORT-ADDRESS-MIB.txt +421 -0
  120. data/lib/telemetry/snmp/mibs/TUNNEL-MIB.txt +738 -0
  121. data/lib/telemetry/snmp/mibs/UCD-DEMO-MIB.txt +74 -0
  122. data/lib/telemetry/snmp/mibs/UCD-DISKIO-MIB.txt +171 -0
  123. data/lib/telemetry/snmp/mibs/UCD-DLMOD-MIB.txt +124 -0
  124. data/lib/telemetry/snmp/mibs/UCD-IPFWACC-MIB.txt +327 -0
  125. data/lib/telemetry/snmp/mibs/UCD-SNMP-MIB.txt +1712 -0
  126. data/lib/telemetry/snmp/mibs/UDP-MIB.txt +549 -0
  127. data/lib/telemetry/snmp/publisher.rb +130 -0
  128. data/lib/telemetry/snmp/version.rb +7 -0
  129. data/sourcehawk.yml +4 -0
  130. data/telemetry-snmp.gemspec +48 -0
  131. metadata +456 -0
data/NOTICE.txt ADDED
@@ -0,0 +1,9 @@
1
+ Telemetry::Snmp
2
+ Copyright 2021 Optum
3
+
4
+ Project Description:
5
+ ====================
6
+ A Telemetry gem used to collect SNMP metrics and output them to Telemetry::AMQP in line protocol format
7
+
8
+ Author(s):
9
+ Esity
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Telemetry::Snmp
2
+
3
+ ### Telemetry::Snmp Collector Service
4
+ This is a servce that runs and collects SNMP metrics at whatever frequency is defined inside the basement. As you need
5
+ additional collectors, you can scale this out to give you more parallel workers
6
+
7
+ You can start this service by running
8
+ ```ruby
9
+ bundle update
10
+ bundle exec exe/snmp_collector
11
+ ```
12
+
13
+
14
+ ### Telemetry::Snmp::API
15
+ The API allows for you to remotely CRUD devices, oids, users, device credentials, etc
16
+ The Routes are available via a [postman json](https://github.com/Optum/telemetry-snmp/blob/main/telemetry-snmp.json)
17
+
18
+ ## OID Mappings
19
+ The oid_walks table is the most utilized and probably what you are looking for.
20
+ Table Layout
21
+ ```json
22
+ {
23
+ "oid": "the oid you want to grab metrics from(walk)",
24
+ "oid_index": "the oid to use as an index for naming",
25
+ "measurement_name": "what name to name the measurement",
26
+ "active": 1
27
+ }
28
+ ```
29
+
30
+
31
+ ## Settings
32
+ Telemetry::Snmp::Publisher
33
+ ```ruby
34
+ ENV['telemetry.snmp.amqp.username'] = 'guest'
35
+ ENV['telemetry.snmp.amqp.password'] = 'guest'
36
+ ENV['telemetry.snmp.amqp.nodes'] = 'localhost'
37
+ ENV['telemetry.snmp.amqp.vhost'] = 'telemetry'
38
+ ENV['telemetry.snmp.amqp.port'] = '5672'
39
+ ENV['telemetry.snmp.amqp.use_ssl'] = 'false'
40
+ ENV['telemetry.snmp.amqp.exchange_name'] = 'telemetry.snmp'
41
+ ```
42
+
43
+ Telemetry::Snmp::Data
44
+ ```ruby
45
+ ENV['telemetry.snmp.data.adapter'] = 'mysql2'
46
+ ENV['telemetry.snmp.data.username'] = 'root'
47
+ ENV['telemetry.snmp.data.password'] = ''
48
+ ENV['telemetry.snmp.data.database'] = 'telemetry_snmp'
49
+ ENV['telemetry.snmp.data.host'] = '127.0.0.1'
50
+ ENV['telemetry.snmp.data.port'] = '3306'
51
+ ENV['telemetry.snmp.data.max_connections'] = '16'
52
+ ENV['telemetry.snmp.data.pool_timeout'] = '2'
53
+ ENV['telemetry.snmp.data.preconnect'] = 'concurrently'
54
+ ```
data/attribution.txt ADDED
@@ -0,0 +1 @@
1
+ Add attributions here.
data/config.ru ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+
5
+ require 'puma'
6
+ require 'rack'
7
+ require 'sinatra'
8
+ require 'oj'
9
+ require 'multi_json'
10
+
11
+ require 'telemetry/snmp'
12
+ require 'telemetry/snmp/api'
13
+
14
+ Telemetry::Snmp::Data.start!
15
+ run Telemetry::Snmp::API
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'telemetry/snmp'
4
+ Telemetry::Snmp.bootstrap
5
+
6
+ trap('SIGTERM') { @quit = true }
7
+ trap('SIGHUP') { @quit = true }
8
+ trap('SIGINT') { @quit = true }
9
+
10
+ @quit = false
11
+ until @quit
12
+ @lines = []
13
+ Telemetry::Snmp::Data::Model::Device.each do |row|
14
+ next if row.values[:last_polled].to_i + row.values[:frequency] > Time.now.to_i
15
+
16
+ fields = {}
17
+ tags = {
18
+ hostname: row.values[:hostname],
19
+ ip_address: row.values[:ip_address],
20
+ env: row.values[:environment],
21
+ dc: row.values[:datacenter],
22
+ zone: row.values[:zone],
23
+ influxdb_node_group: 'snmp'
24
+ }
25
+
26
+ Telemetry::Snmp::Data::Model::OID.each do |oid_row|
27
+ oid_value = Telemetry::Snmp::Client.oid_value(row[:hostname], oid_row.values[:oid])
28
+ next if oid_value.nil?
29
+ next unless oid_value.is_a?(Integer) || oid_value.is_a?(Float)
30
+
31
+ fields[oid_row.values[:name]] = "#{Telemetry::Snmp::Client.oid_value(row[:hostname], oid_row.values[:oid])}i"
32
+ rescue StandardError => e
33
+ Telemetry::Logger.error "#{e.class}: #{e.message}"
34
+ end
35
+
36
+ @lines.push Telemetry::Metrics::Parser.to_line_protocol(
37
+ measurement: 'palo_alto_a',
38
+ fields: fields,
39
+ tags: tags,
40
+ timestamp: (DateTime.now.strftime('%Q').to_i * 1000 * 1000)
41
+ )
42
+
43
+ walker = Telemetry::Snmp::Client.grab_oid_metrics(row.values[:hostname])
44
+ Telemetry::Logger.info "Pushing #{walker.count} lines for #{row.values[:hostname]}" unless walker.empty?
45
+ Telemetry::Snmp::Publisher.push_lines(walker) unless walker.empty?
46
+
47
+ row.update(last_polled: Sequel::CURRENT_TIMESTAMP)
48
+ row.save
49
+ rescue StandardError => e
50
+ Telemetry::Logger.error "#{e.class}: #{e.message}"
51
+ end
52
+
53
+ Telemetry::Snmp::Publisher.push_lines(@lines) unless @lines.empty?
54
+ sleep(1)
55
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'telemetry/snmp/version'
4
+ require 'telemetry/logger'
5
+ require 'telemetry/metrics/parser'
6
+ require 'telemetry/snmp/data'
7
+ require 'telemetry/snmp/client'
8
+ require 'telemetry/snmp/publisher'
9
+
10
+ module Telemetry
11
+ module Snmp
12
+ class << self
13
+ def bootstrap
14
+ Telemetry::Logger.setup(level: 'info')
15
+ Telemetry::Logger.info "Starting Telemetry::Snmp v#{Telemetry::Snmp::VERSION}"
16
+ Telemetry::Snmp::Data.start!
17
+ Telemetry::Snmp::Client.load_mibs
18
+ Telemetry::Snmp::Publisher.start!
19
+ Telemetry::Logger.info 'Telemetry::Snmp bootstrapped!'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,55 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/contrib'
3
+ require 'sinatra/multi_route'
4
+ require 'sinatra/respond_with'
5
+ require 'sinatra/custom_logger'
6
+ require 'sinatra/namespace'
7
+ require 'oj'
8
+
9
+ require 'telemetry/snmp/controllers/device_creds'
10
+ require 'telemetry/snmp/controllers/devices'
11
+ require 'telemetry/snmp/controllers/oid_groups'
12
+ require 'telemetry/snmp/controllers/oids'
13
+ require 'telemetry/snmp/controllers/users'
14
+ require 'telemetry/snmp/controllers/walks'
15
+
16
+ module Telemetry
17
+ module Snmp
18
+ class API < Sinatra::Base
19
+ register Sinatra::JSON
20
+ register Sinatra::Namespace
21
+ register Sinatra::RespondWith
22
+
23
+ error do
24
+ content_type :json
25
+ status 500
26
+
27
+ { result: 'error', message: env['sinatra.error'].message }.to_json
28
+ end
29
+
30
+ before do
31
+ headers 'Access-Control-Allow-Origin' => '*',
32
+ 'Access-Control-Allow-Methods' => %w[OPTIONS GET POST]
33
+ end
34
+
35
+ after do
36
+ content_type :json
37
+ response.body = Oj.dump(response.body, mode: :compat) unless response.body.is_a? String
38
+ end
39
+
40
+ get '/version' do
41
+ {
42
+ version: Telemetry::Snmp::VERSION,
43
+ migration_version: Telemetry::Snmp::Data.migration_version
44
+ }
45
+ end
46
+
47
+ namespace('/users') { register Telemetry::Snmp::Controller::Users }
48
+ namespace('/devices/creds') { register Telemetry::Snmp::Controller::DeviceCreds }
49
+ namespace('/devices') { register Telemetry::Snmp::Controller::Devices }
50
+ namespace('/oid_groups') { register Telemetry::Snmp::Controller::OIDGroups }
51
+ namespace('/oid') { register Telemetry::Snmp::Controller::OIDs }
52
+ namespace('/walks') { register Telemetry::Snmp::Controller::Walks }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,54 @@
1
+ require 'net/ldap'
2
+ require 'telemetry/snmp/auth/defaults'
3
+
4
+ module Telemetry
5
+ module Snmp
6
+ class Auth
7
+ include Telemetry::Snmp::AuthDefaults
8
+
9
+ def initialize(username:, **opts)
10
+ @username = username
11
+ @details = {}
12
+ @opts = opts
13
+ end
14
+
15
+ def process_result(result)
16
+ unless result.is_a? Net::LDAP::Entry
17
+ @success = false
18
+ return
19
+ end
20
+ @details[:username] = result.sAMAccountName.first
21
+ @details[:email] = result.mail.first
22
+ @details[:first] = result.givenName.first
23
+ @details[:last] = result.sn.first
24
+ @success = true
25
+ end
26
+
27
+ def search_user(ldap, username)
28
+ user_filter = Net::LDAP::Filter.eq('sAMAccountName', username)
29
+
30
+ ldap.search(base: treebase, filter: user_filter, attrs: attrs, return_result: false) do |entry|
31
+ @details[:group_access] = entry.memberof.include?("CN=#{admin_group}, #{treebase}")
32
+ return entry
33
+ end
34
+ end
35
+
36
+ def auth_with_service(password)
37
+ options = defaults
38
+ options[:auth] = defaults_auth
39
+ result = provider.new(options).bind_as(base: defaults[:base], attributes: attrs, filter: filter, password: password) # rubocop:disable Layout/LineLength
40
+ process_result(result.first)
41
+ end
42
+
43
+ def auth_without_service(password)
44
+ options = { host: defaults[:host], port: defaults[:port] }
45
+ options[:auth] = { password: password, username: @username, method: :simple }
46
+ ldap = provider.new(options)
47
+ @success = ldap.bind
48
+ return unless @success
49
+
50
+ process_result(search_user(ldap, @username))
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module Telemetry
2
+ module Snmp
3
+ module AuthDefaults
4
+ def opts
5
+ @opts ||= {}
6
+ end
7
+
8
+ def attrs
9
+ %w[mail cn sn objectclass givenName sAMAccountName MemberOf]
10
+ end
11
+
12
+ def treebase
13
+ opts[:treebase] || ENV['treebase'] || 'CN=Users,DC=com'
14
+ end
15
+
16
+ def ldap_host
17
+ opts[:ldap_host] || ENV['ldap_host'] || 'localhost'
18
+ end
19
+
20
+ def ldap_port
21
+ opts[:ldap_port] || ENV['ldap_host'] || '389'
22
+ end
23
+
24
+ def provider
25
+ Net::LDAP
26
+ end
27
+
28
+ def filter(username = @username)
29
+ "(sAMAccountName=#{username})"
30
+ end
31
+
32
+ def admin_group
33
+ opts[:admin_group] || ENV['ldap_admin_group']
34
+ end
35
+
36
+ def users_group
37
+ opts[:users_group] || ENV['ldap_users_group']
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,104 @@
1
+ require 'socket'
2
+ require 'netsnmp'
3
+
4
+ module Telemetry
5
+ module Snmp
6
+ module Client
7
+ @connections = {}
8
+
9
+ class << self
10
+ def load_mibs
11
+ ENV['MIBDIRS'] = "#{__dir__}/mibs"
12
+ NETSNMP::MIB.load_defaults
13
+ # NETSNMP::MIB.load("#{__dir__}/mibs/PAN-COMMON-MIB.my")
14
+ # NETSNMP::MIB.load("#{__dir__}/mibs/PAN-ENTITY-EXT-MIB.my")
15
+ # NETSNMP::MIB.load("#{__dir__}/mibs/PAN-GLOBAL-REG-MIB.my")
16
+ # NETSNMP::MIB.load("#{__dir__}/mibs/PAN-GLOBAL-TC-MIB.my")
17
+ # NETSNMP::MIB.load("#{__dir__}/mibs/PAN-LC-MIB.my")
18
+ # NETSNMP::MIB.load("#{__dir__}/mibs/PAN-PRODUCT-MIB.my")
19
+ end
20
+
21
+ def connection(host)
22
+ return @connections[host.to_sym] if @connections.key? host.to_sym
23
+
24
+ dataset = Telemetry::Snmp::Data::Model::Device[hostname: host]
25
+
26
+ @connections[host.to_sym] = NETSNMP::Client.new(
27
+ host: dataset.values[:ip_address],
28
+ port: dataset.values[:port],
29
+ username: dataset.device_cred.values[:username],
30
+ auth_password: dataset.device_cred.values[:auth_password],
31
+ auth_protocol: dataset.device_cred.values[:auth_protocol].to_sym,
32
+ priv_password: dataset.device_cred.values[:priv_password],
33
+ priv_protocol: dataset.device_cred.values[:priv_protocol].to_sym,
34
+ security_level: dataset.device_cred.values[:security_level].to_sym
35
+ )
36
+ end
37
+
38
+ def oid_value(host, oid)
39
+ connection(host).get(oid: oid)
40
+ rescue StandardError
41
+ nil
42
+ end
43
+
44
+ def oid_walk(host, oid)
45
+ results = []
46
+ connection(host).walk(oid: oid).each do |oid_code, value|
47
+ hash = { oid_code: oid_code, value: value }
48
+ begin
49
+ ident = NETSNMP::MIB.identifier(oid_code)
50
+
51
+ hash[:identifier] = ident.first
52
+ rescue StandardError
53
+ # literally do nothing
54
+ end
55
+ results.push hash
56
+ end
57
+
58
+ results
59
+ end
60
+
61
+ def grab_oid_metrics(hostname)
62
+ device = Telemetry::Snmp::Data::Model::Device[hostname: hostname]
63
+ @lines = []
64
+ Telemetry::Snmp::Data::Model::OIDWalks.where(:active).each do |row|
65
+ index = {}
66
+ Telemetry::Snmp::Client.oid_walk(device.values[:hostname], row.values[:oid_index]).each do |hash|
67
+ index[hash[:oid_code].delete_prefix("#{row.values[:oid_index]}.")] = hash[:value].gsub(%r{\\/}, '.')
68
+ end
69
+
70
+ timestamp = DateTime.now.strftime('%Q').to_i * 1000 * 1000
71
+ Telemetry::Snmp::Client.oid_walk(device.values[:hostname], row.values[:oid_walk]).each do |walk|
72
+ key = walk[:oid_code].split('.').last
73
+ next if walk[:value].is_a? String
74
+ next if walk[:value].nil?
75
+
76
+ fields = {}
77
+ fields[walk[:identifier]] = "#{walk[:value]}i"
78
+ tags = {
79
+ hostname: device.values[:hostname],
80
+ interface: index[key],
81
+ ip_address: device.values[:ip_address],
82
+ zone: device.values[:zone],
83
+ env: device.values[:environment],
84
+ dc: device.values[:datacenter],
85
+ influxdb_node_group: 'snmp'
86
+ }
87
+
88
+ line = Telemetry::Metrics::Parser.to_line_protocol(
89
+ measurement: row.values[:measurement],
90
+ fields: fields,
91
+ tags: tags,
92
+ timestamp: timestamp
93
+ )
94
+
95
+ @lines.push line
96
+ end
97
+ end
98
+
99
+ @lines
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,105 @@
1
+ require 'sinatra/extension'
2
+
3
+ module Telemetry
4
+ module Snmp
5
+ module Controller
6
+ module DeviceCreds
7
+ extend Sinatra::Extension
8
+ # id, port, username, auth_password, auth_protocol, priv_password, priv_protocol, security_level
9
+
10
+ get '' do
11
+ results = {}
12
+
13
+ Telemetry::Snmp::Data::Model::DeviceCred.all.each do |creds|
14
+ results[creds.values[:id]] = {
15
+ id: creds.values[:id],
16
+ port: creds.values[:port],
17
+ username: creds.values[:username],
18
+ auth_protocol: creds.values[:auth_protcol],
19
+ priv_protocol: creds.values[:priv_protocol],
20
+ security_level: creds.values[:security_level],
21
+ created: creds.values[:created],
22
+ updated: creds.values[:updated]
23
+ }
24
+ end
25
+
26
+ results
27
+ end
28
+
29
+ get '/:id' do
30
+ cred = Telemetry::Snmp::Data::Model::DeviceCred[params[:id]]
31
+ if cred.nil?
32
+ status 404
33
+ return {}
34
+ end
35
+
36
+ results = cred.values.dup
37
+ results.delete(:auth_password)
38
+ results.delete(:priv_password)
39
+
40
+ results
41
+ end
42
+
43
+ post '' do
44
+ body = MultiJson.load(request.body.read, symbolize_keys: true)
45
+
46
+ if params[:username].nil? || params[:auth_password].nil?
47
+ status 400
48
+ {
49
+ error: true,
50
+ username_missing: params[:username].nil?,
51
+ auth_password_missing: params[:auth_password].nil?
52
+ }
53
+ end
54
+ insert = {
55
+ port: body[:port] || 161,
56
+ username: body[:username],
57
+ auth_password: body[:auth_password],
58
+ auth_protocol: body[:auth_protocol] || 'sha',
59
+ priv_password: body[:priv_password],
60
+ priv_protocol: body[:priv_protocol] || 'aes',
61
+ security_level: body[:security_level] || 'auth_priv',
62
+ created: Sequel::CURRENT_TIMESTAMP
63
+ }
64
+
65
+ { id: Telemetry::Snmp::Data::Model::DeviceCred.insert(**insert), username: insert[:username] }
66
+ end
67
+
68
+ put '/:id' do
69
+ status 405
70
+ { error: true, message: 'puts not supported', id: params[:id] }
71
+ end
72
+
73
+ patch '/:id' do
74
+ cred = Telemetry::Snmp::Data::Model::DeviceCred[params[:id]]
75
+ if cred.nil?
76
+ status 404
77
+ return { error: true, id: params[:id], message: "cannot find #{params[:id]}" }
78
+ end
79
+
80
+ body = MultiJson.load(request.body.read, symbolize_keys: true)
81
+ update = {}
82
+ fields = %i[port username auth_password auth_protocol priv_password priv_protocol security_level]
83
+ fields.each { |field| update[field] = body[field] if body.key? field }
84
+
85
+ if update.empty?
86
+ status 400
87
+ return { error: true, message: 'no valid fields to update' }
88
+ end
89
+
90
+ update[:updated] = Sequel::CURRENT_TIMESTAMP
91
+ cred.update(**update)
92
+ { error: false, updated_field: update.keys, id: params[:id] }
93
+ end
94
+
95
+ delete '/:id' do
96
+ cred = Telemetry::Snmp::Data::Model::DeviceCred[params[:id]]
97
+ status 404 if cred.nil?
98
+ return { error: true, message: "#{params[:id]} not found" } if cred.nil?
99
+
100
+ { error: !result.delete, id: params[:id] }
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end