From 20ec3fb05a6e31b35f88a22ea294dfa768c577b5 Mon Sep 17 00:00:00 2001 From: Adam Gardner Date: Tue, 13 Apr 2021 12:57:46 -1000 Subject: [PATCH 1/3] Allow reading advanced config from JSON file, allow retrieving EC2 metadata facts --- .../util/network_device/mikrotik/facts.rb | 54 ++++++++++++++++--- .../util/network_device/transport/mikrotik.rb | 37 ++++++++++--- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/lib/puppet/util/network_device/mikrotik/facts.rb b/lib/puppet/util/network_device/mikrotik/facts.rb index b52feeb..099f743 100644 --- a/lib/puppet/util/network_device/mikrotik/facts.rb +++ b/lib/puppet/util/network_device/mikrotik/facts.rb @@ -2,7 +2,7 @@ class Puppet::Util::NetworkDevice::Mikrotik::Facts attr_reader :transport - + def initialize(transport) @transport = transport end @@ -12,20 +12,60 @@ def connection end def retrieve - facts_raw = {} - system_resources = connection.get_reply("/system/resource/getall") - system_resources.each do |system_resource| + facts_raw = {} + system_resources = connection.get_reply("/system/resource/getall") + system_resources.each do |system_resource| if system_resource.key?('!re') facts_raw = system_resource.reject { |k, v| ['!re', '.tag'].include? k } end end - + facts = {} facts_raw.each do |k, v| new_key = k.gsub(/-/, '_') facts[new_key] = v end - - facts + + facts.merge(get_other_facts) + end + + def get_other_facts + other_facts = { + 'osfamily' => 'Mikrotik', + 'os' => { + 'family' => 'Mikrotik', + 'name' => 'RouterOS' + } + } + other_facts['ec2_metadata'] = ec2_metadata if transport.include_ec2_facts? + other_facts + end + + def ec2_metadata + { + 'instance-id' => ec2('instance-id'), + 'instance-type' => ec2('instance-type'), + 'local-ipv4' => ec2('local-ipv4'), + 'mac' => ec2('mac'), + 'public-ipv4' => ec2('public-ipv4'), + 'placement' => { + 'availability-zone' => ec2('placement/availability-zone'), + }, + } + end + + def ec2(path) + params = { + 'url' => "http://169.254.169.254/latest/meta-data/#{path}", + 'mode' => 'http', + 'output' => 'user', + } + p_array = params.map { |k,v| "=#{k}=#{v}" } + reply = connection.get_reply('/tools/fetch',*p_array) + if result = reply.find_sentence('data') + result['data'] + else + nil + end end end \ No newline at end of file diff --git a/lib/puppet/util/network_device/transport/mikrotik.rb b/lib/puppet/util/network_device/transport/mikrotik.rb index 79c6f5a..e0e06db 100644 --- a/lib/puppet/util/network_device/transport/mikrotik.rb +++ b/lib/puppet/util/network_device/transport/mikrotik.rb @@ -9,13 +9,38 @@ class Puppet::Util::NetworkDevice::Transport::Mikrotik < Puppet::Util::NetworkDe def initialize(url, _options = {}) require 'uri' - + url_object = URI(url) - if (url_object.scheme == 'api') - @connection = MTik::Connection.new :host => url_object.host, :user => url_object.user, :pass => url_object.password, :unecrypted_plaintext => true, :conn_timeout => 10 - else - raise "The Mikrotik module currently only support API access. Use api:// in URL." - end + case url_object.scheme + when 'api' + @connection = MTik::Connection.new :host => url_object.host, :user => url_object.user, :pass => url_object.password, :unencrypted_plaintext => true, :conn_timeout => 10 + when 'file' + config = JSON.parse(File.read(url_object.path)) + + raise "When using an advanced config file, the 'host' option is required" unless config['host'] + + opts = { + host: config['host'], + user: config['user'], + pass: config['password'], + conn_timeout: 10, + use_ssl: config['use_ssl'], + }.compact! + + opts[:port] = config['port'].to_i if config['port'] + opts[:conn_timeout] = config['conn_timeout'].to_i if config['conn_timeout'] + opts[:cmd_timeout] = config['cmd_timeout'].to_i if config['cmd_timeout'] + opts[:unencrypted_plaintext] = config.has_key?('unencrypted_plaintext') ? config['unencrypted_plaintext'] : !config['use_ssl'] + + @connection = MTik::Connection.new(opts) + @include_ec2_facts = config['include_ec2_facts'] + else + raise "The Mikrotik module currently only support API access. Use either api:// in URL, or use file:// for advanced config from a separate JSON file." + end + end + + def include_ec2_facts? + !!@include_ec2_facts end end \ No newline at end of file From 66cd7e3a314f598a6ff37a2deb28983f7d575e9b Mon Sep 17 00:00:00 2001 From: Adam Gardner Date: Tue, 13 Apr 2021 13:34:00 -1000 Subject: [PATCH 2/3] Add additional debug logging --- lib/puppet/util/network_device/mikrotik/facts.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/puppet/util/network_device/mikrotik/facts.rb b/lib/puppet/util/network_device/mikrotik/facts.rb index 099f743..9563f89 100644 --- a/lib/puppet/util/network_device/mikrotik/facts.rb +++ b/lib/puppet/util/network_device/mikrotik/facts.rb @@ -13,7 +13,9 @@ def connection def retrieve facts_raw = {} + Puppet.info("Getting device facts.") system_resources = connection.get_reply("/system/resource/getall") + Puppet.debug("Got device facts: #{system_resources.inspect}") system_resources.each do |system_resource| if system_resource.key?('!re') facts_raw = system_resource.reject { |k, v| ['!re', '.tag'].include? k } @@ -42,6 +44,7 @@ def get_other_facts end def ec2_metadata + Puppet.info('Getting EC2 metadata facts from device.') { 'instance-id' => ec2('instance-id'), 'instance-type' => ec2('instance-type'), @@ -61,7 +64,9 @@ def ec2(path) 'output' => 'user', } p_array = params.map { |k,v| "=#{k}=#{v}" } + Puppet.debug("Requested device fetch #{params.inspect}") reply = connection.get_reply('/tools/fetch',*p_array) + Puppet.debug("Got response: #{reply.inspect}") if result = reply.find_sentence('data') result['data'] else From 53900cb22e32d9ec007494fbfec937289e990e42 Mon Sep 17 00:00:00 2001 From: Adam Gardner Date: Tue, 13 Apr 2021 13:52:39 -1000 Subject: [PATCH 3/3] Fix typo --- lib/puppet/util/network_device/mikrotik/facts.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/util/network_device/mikrotik/facts.rb b/lib/puppet/util/network_device/mikrotik/facts.rb index 9563f89..030ab6f 100644 --- a/lib/puppet/util/network_device/mikrotik/facts.rb +++ b/lib/puppet/util/network_device/mikrotik/facts.rb @@ -65,7 +65,7 @@ def ec2(path) } p_array = params.map { |k,v| "=#{k}=#{v}" } Puppet.debug("Requested device fetch #{params.inspect}") - reply = connection.get_reply('/tools/fetch',*p_array) + reply = connection.get_reply('/tool/fetch',*p_array) Puppet.debug("Got response: #{reply.inspect}") if result = reply.find_sentence('data') result['data']