telemetry-snmp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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