Module: TrainPlugins::Juniper::Platform
- Included in:
- Connection
- Defined in:
- lib/train-juniper/platform.rb
Overview
This module is mixed into the Connection class to provide platform detection
Platform detection mixin for Juniper network devices
Constant Summary collapse
- PLATFORM_NAME =
Platform name constant for consistency
'juniper'
Instance Method Summary collapse
-
#detect_attribute(attribute_name, command = 'show version') {|String| ... } ⇒ String?
private
Generic detection helper for version and architecture.
-
#detect_junos_architecture ⇒ String?
private
Detect JunOS architecture from device output.
-
#detect_junos_serial ⇒ String?
private
Detect JunOS serial number from device output.
-
#detect_junos_version ⇒ String?
private
Detect JunOS version from device output.
-
#extract_architecture_from_xml(output) ⇒ String?
private
Extract architecture string from JunOS show version XML output.
-
#extract_from_xml(output, xpath_patterns, command_desc) {|REXML::Element| ... } ⇒ String?
private
Generic XML extraction helper.
-
#extract_serial_from_xml(output) ⇒ String?
private
Extract serial number from JunOS chassis hardware XML output.
-
#extract_version_from_xml(output) ⇒ String?
private
Extract version string from JunOS show version XML output.
-
#platform ⇒ Train::Platform
Platform detection for Juniper network devices.
Instance Method Details
#detect_attribute(attribute_name, command = 'show version') {|String| ... } ⇒ String? (private)
Generic detection helper for version and architecture
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/train-juniper/platform.rb', line 88 def detect_attribute(attribute_name, command = 'show version', &extraction_block) cache_var = "@detected_#{attribute_name}" return instance_variable_get(cache_var) if instance_variable_defined?(cache_var) unless respond_to?(:run_command_via_connection) logger&.debug('run_command_via_connection not available yet') return instance_variable_set(cache_var, nil) end logger&.debug("Mock mode: #{@options&.dig(:mock)}, Connected: #{connected?}") begin return instance_variable_set(cache_var, nil) unless connected? # Reuse cached command result if available result = @cached_show_version_result || run_command_via_connection(command) @cached_show_version_result ||= result if command == 'show version' && result&.exit_status&.zero? return instance_variable_set(cache_var, nil) unless result&.exit_status&.zero? value = extraction_block.call(result.stdout) if value logger&.debug("Detected #{attribute_name}: #{value}") instance_variable_set(cache_var, value) else logger&.debug("Could not parse #{attribute_name} from: #{result.stdout[0..100]}") instance_variable_set(cache_var, nil) end rescue StandardError => e logger&.debug("#{attribute_name} detection failed: #{e.}") instance_variable_set(cache_var, nil) end end |
#detect_junos_architecture ⇒ String? (private)
This runs safely after the connection is established
Detect JunOS architecture from device output
146 147 148 |
# File 'lib/train-juniper/platform.rb', line 146 def detect_junos_architecture detect_attribute('junos_architecture', 'show version | display xml') { |output| extract_architecture_from_xml(output) } end |
#detect_junos_serial ⇒ String? (private)
This runs safely after the connection is established
Detect JunOS serial number from device output
183 184 185 |
# File 'lib/train-juniper/platform.rb', line 183 def detect_junos_serial detect_attribute('junos_serial', 'show chassis hardware | display xml') { |output| extract_serial_from_xml(output) } end |
#detect_junos_version ⇒ String? (private)
This runs safely after the connection is established
Detect JunOS version from device output
126 127 128 |
# File 'lib/train-juniper/platform.rb', line 126 def detect_junos_version detect_attribute('junos_version', 'show version | display xml') { |output| extract_version_from_xml(output) } end |
#extract_architecture_from_xml(output) ⇒ String? (private)
Extract architecture string from JunOS show version XML output
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/train-juniper/platform.rb', line 153 def extract_architecture_from_xml(output) xpath_patterns = [ '//product-model', '//software-information/product-model', '//chassis-inventory/chassis/description' ] extract_from_xml(output, xpath_patterns, 'show version | display xml') do |element| model = element.text.strip # Map model names to architecture case model when /SRX\d+/i 'x86_64' # Most SRX models are x86_64 when /MX\d+/i 'x86_64' # MX routers are typically x86_64 when /EX\d+/i 'arm64' # Many EX switches use ARM when /QFX\d+/i 'x86_64' # QFX switches typically x86_64 else # Default to x86_64 for unknown models 'x86_64' end end end |
#extract_from_xml(output, xpath_patterns, command_desc) {|REXML::Element| ... } ⇒ String? (private)
Generic XML extraction helper
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/train-juniper/platform.rb', line 62 def extract_from_xml(output, xpath_patterns, command_desc) return nil if output.nil? || output.empty? doc = REXML::Document.new(output) # Try each XPath pattern until we find an element element = nil xpath_patterns.each do |xpath| element = doc.elements[xpath] break if element end return nil unless element # If block given, let it process the element, otherwise return text block_given? ? yield(element) : element.text&.strip rescue StandardError => e logger&.warn("Failed to parse XML output from '#{command_desc}': #{e.}") nil end |
#extract_serial_from_xml(output) ⇒ String? (private)
Extract serial number from JunOS chassis hardware XML output
190 191 192 193 194 195 196 197 198 |
# File 'lib/train-juniper/platform.rb', line 190 def extract_serial_from_xml(output) xpath_patterns = [ '//chassis/serial-number', '//chassis-sub-module/serial-number', '//module/serial-number[1]' ] extract_from_xml(output, xpath_patterns, 'show chassis hardware | display xml') end |
#extract_version_from_xml(output) ⇒ String? (private)
Extract version string from JunOS show version XML output
133 134 135 136 137 138 139 140 141 |
# File 'lib/train-juniper/platform.rb', line 133 def extract_version_from_xml(output) xpath_patterns = [ '//junos-version', '//package-information/name[text()="junos"]/following-sibling::comment', '//software-information/version' ] extract_from_xml(output, xpath_patterns, 'show version | display xml') end |
#platform ⇒ Train::Platform
Uses force_platform! to bypass Train's automatic detection
Platform detection for Juniper network devices
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/train-juniper/platform.rb', line 23 def platform # Return cached platform if already computed return @platform if defined?(@platform) # Register the juniper platform in Train's platform registry # JunOS devices are FreeBSD-based, so inherit from bsd family for InSpec resource compatibility # This allows InSpec resources like 'command' to work with Juniper devices Train::Platforms.name(PLATFORM_NAME).title('Juniper JunOS').in_family('bsd') # Try to detect actual JunOS version and architecture from device device_version = detect_junos_version || TrainPlugins::Juniper::VERSION device_arch = detect_junos_architecture || 'unknown' logger&.debug("Detected device architecture: #{device_arch}") # Bypass Train's platform detection and declare our known platform # Include architecture in the platform details to ensure it's properly set platform_details = { release: device_version, arch: device_arch } platform_obj = force_platform!(PLATFORM_NAME, platform_details) logger&.debug("Set platform data: #{platform_obj.platform}") # Log platform detection results if logging helpers available log_platform_detection(PLATFORM_NAME, device_version) if respond_to?(:log_platform_detection) # Cache the platform object to prevent repeated calls @platform = platform_obj end |