Skip to content

Juniper XML/RPC Learnings - Platform Detection

Key Discovery

While implementing the uri and unique_identifier methods to fix the UUID warning (issue #3), we discovered that Juniper's official Ruby library (ruby-junos-ez-stdlib) exclusively uses XML/RPC for all device interactions.

Research Findings

1. Juniper's Official Approach

From analyzing ruby-junos-ez-stdlib:

# Chassis information (including serial number)
inv_info = ndev.rpc.get_chassis_inventory
facts[:serialnumber] = chassis.xpath('serial-number').text

# Version information
swver = ndev.rpc.command "show version"
facts[:version] = swver.xpath('//junos-version').text

Key insight: Juniper NEVER uses regex parsing of text output in their official library.

2. CLI to XML/RPC Mapping

CLI Command XML RPC Output via SSH
show chassis hardware <get-chassis-inventory> Add \| display xml
show version <get-software-information> Add \| display xml
show system information <get-system-information> Add \| display xml

Important: show chassis hardware | display xml produces identical output to the RPC call.

3. Current Implementation vs Best Practice

Aspect Current (Text + Regex) Juniper Official (XML)
Reliability Brittle - format changes break regex Stable - structured data
Maintenance Complex regex patterns Simple XPath queries
Compatibility Works on all versions Works on all modern JunOS
Performance Slightly faster Slightly slower (XML parsing)
Future-proof No - CLI output can change Yes - XML schema is stable

4. Protocol Differences

  • Juniper stdlib: Uses NETCONF protocol (native XML)
  • Train-juniper: Uses SSH protocol (text by default)
  • Bridge: SSH can get same XML with | display xml

Decision: Adopt XML Approach

We will update our platform detection to use XML output, following Juniper's official patterns. This ensures:

  1. Stability: XML schema rarely changes
  2. Compatibility: Matches official Juniper automation
  3. Maintainability: No complex regex patterns
  4. Reliability: Structured data parsing

Implementation Pattern

# New pattern following Juniper's approach
def detect_junos_serial
  detect_attribute('junos_serial', 'show chassis hardware | display xml') { |output| 
    extract_serial_from_xml(output) 
  }
end

def extract_serial_from_xml(output)
  require 'rexml/document'
  doc = REXML::Document.new(output)

  # Use same XPath as Juniper's official library
  serial_element = doc.elements['//chassis/serial-number']
  serial_element&.text&.strip
rescue StandardError => e
  logger&.debug("XML parsing failed: #{e.message}")
  nil
end

Affected Components

Platform Module (lib/train-juniper/platform.rb)

  • detect_junos_version - Should use XML
  • detect_junos_architecture - Should use XML
  • detect_junos_serial - Must use XML (current work)

Mock Responses (lib/train-juniper/helpers/mock_responses.rb)

  • All mock responses need XML versions
  • Keep text versions for backward compatibility

Tests

  • Platform tests need XML fixtures
  • Connection tests need XML responses
  • Mock infrastructure needs updating

Benefits of This Approach

  1. Following Industry Standards: Aligning with Juniper's official automation approach
  2. Better Error Handling: XML parsing errors are clearer than regex mismatches
  3. Easier Debugging: Can validate XML structure independently
  4. Future Features: Easy to extract additional fields from XML
  5. Cross-Platform: Same code works via NETCONF or SSH

Risks and Mitigation

Risk Mitigation
Older JunOS without XML support Implement text fallback
XML parsing overhead Minimal impact, benefits outweigh
Breaking existing code Gradual migration, keep text methods
Test suite updates Update incrementally

References