Skip to content

Multi-Version Support in Terraform Provider for Cisco IOS-XR & 25.1X support - #323

Open
hayibrah wants to merge 8 commits into
CiscoDevNet:mainfrom
hayibrah:feature/muli-iosxr-version-support
Open

Multi-Version Support in Terraform Provider for Cisco IOS-XR & 25.1X support #323
hayibrah wants to merge 8 commits into
CiscoDevNet:mainfrom
hayibrah:feature/muli-iosxr-version-support

Conversation

@hayibrah

@hayibrah hayibrah commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

Overview

The provider now supports multiple IOS-XR versions (e.g., 24.4, 25.2) with intelligent version-aware validation that:

  • Validates field compatibility before sending to devices
  • Enforces version-specific integer ranges from YANG models
  • Only generates validation code when resources have version differences

Key Changes

1. Automatic IOS-XR Version Detection (Optional iosxr_version)

The provider now automatically detects IOS-XR version from devices via gNMI when iosxr_version is not specified:

provider "iosxr" {
  # iosxr_version is now optional - auto-detected from device
  devices = [
    { name = "router1", host = "10.1.1.1" }  # Auto-detects 24.4
  ]
}

Features:

  • Queries /Cisco-IOS-XR-cli-cfg:cli to extract version from CLI config header
  • In-memory caching (sync.Map) - no redundant queries within a run
  • Per-device version support for mixed-version environments
  • Graceful fallback - requires explicit iosxr_version if detection fails

2. Unified Validation (3 → 1 Function)

if !helpers.Validate(r.data.Version, plan, &resp.Diagnostics) {
    return
}

Replaces three separate validation calls. Only generated when resource has version differences.

3. Direct Registration (Removed init() Functions)

func (p *iosxrProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
    return []func() datasource.DataSource{
        NewAAADataSource,
        NewAAAAccountingDataSource,
        // ...
    }
}

Resources and datasources are now registered directly in provider.go instead of using init() functions.

4. YANG-Based Range Constraints

Integer ranges automatically extracted from YANG models per version:

  • Version 24.4: endpoint_default_probe_tx_interval range: 30000-15000000
  • Version 25.2: endpoint_default_probe_tx_interval range: 3300-15000000

Configuration Examples

Provider Setup

provider "iosxr" {
  alias         = "v244"
  host          = "192.168.1.1"
  iosxr_version = "24.4"  # optional
}

provider "iosxr" {
  alias         = "v252"
  host          = "192.168.1.2"
  iosxr_version = "25.2"  # optional
}

Example 1: Version-Specific Ranges

# FAILS for v244 (min: 30000)
resource "iosxr_performance_measurement_liveness_profile" "v244" {
  provider = iosxr.v244
  endpoint_default_probe_tx_interval = 5000  # ERROR
}

# SUCCEEDS for v252 (min: 3300)
resource "iosxr_performance_measurement_liveness_profile" "v252" {
  provider = iosxr.v252
  endpoint_default_probe_tx_interval = 5000  # OK
}

Example 2: Removed Field

# OK in v244
resource "iosxr_crypto" "v244" {
  provider = iosxr.v244
  ca_trustpoints = [{
    trustpoint_name = "TP1"
    method_est_credential_certificate = "CERT1"  # Available
  }]
}

# ERROR in v252
resource "iosxr_crypto" "v252" {
  provider = iosxr.v252
  ca_trustpoints = [{
    trustpoint_name = "TP2"
    method_est_credential_certificate = "CERT2"  # Removed
  }]
}

Example 3: Added Field

# ERROR in v244
resource "iosxr_crypto" "v244" {
  provider = iosxr.v244
  ca_trustpoints = [{
    enrollment_authentication_profile = "PROF1"  # Not available
  }]
}

# OK in v252
resource "iosxr_crypto" "v252" {
  provider = iosxr.v252
  ca_trustpoints = [{
    enrollment_authentication_profile = "PROF2"  # Available
  }]
}

Example 4: Legacy Resource

# OK in v244
resource "iosxr_hostname" "v244" {
  provider = iosxr.v244
  system_network_name = "router-1"
}

# ERROR in v252 (entire resource removed)
resource "iosxr_hostname" "v252" {
  provider = iosxr.v252
  system_network_name = "router-2"
}

How It Works

Validation Flow

  1. Provider reads iosxr_version from configuration (optional - auto-detected if not set)
  2. During Create/Update:
    • Check if fields are supported in the configured version
    • Validate integer values against version-specific ranges
    • Only send to device if validation passes
  3. During Delete:
    • Only check if resource/fields are supported

Validation Only When Needed

Validation code is only generated if a resource has:

  • Fields with AddedInVersion or RemovedInVersion
  • Fields with different VersionRanges across versions
  • Entire resource marked as Legacy in any version

Zero overhead for resources without version differences.

Architecture

Code Organization

terraform-provider-iosxr/
├── gen/
│   ├── generator.go                        # Main generator with version merging logic
│   ├── definitions/
│   │   ├── 24.4/                          # Base version (24.4) definitions
│   │   │   ├── crypto.yaml
│   │   │   ├── hostname.yaml
│   │   │   └── ...
│   │   └── 25.2/                          # Higher version (25.2) definitions
│   │       ├── crypto.yaml                # Overrides/extends base
│   │       ├── hostname.yaml              # Marks resource as legacy
│   │       └── ...
│   ├── models/
│   │   ├── 24.4/                          # YANG models for version 24.4
│   │   └── 25.2/                          # YANG models for version 25.2
│   └── templates/
│       ├── model.go                        # Generates model with version methods
│       ├── resource.go                     # Generates resource with conditional validation
│       ├── data_source.go                  # Generates datasource
│       └── provider.go                     # Generates provider with direct registration
├── internal/provider/
│   ├── helpers/
│   │   ├── version_validation.go          # Unified Validate() function
│   │   └── test_helpers.go                # IosxrVersionAtLeast() for tests
│   ├── model_iosxr_*.go                   # Generated unified models
│   ├── resource_iosxr_*.go                # Generated unified resources
│   └── data_source_iosxr_*.go             # Generated unified datasources
└── examples/
    └── resources/
        └── iosxr_crypto/
            └── resource.tf                 # Example with version comments

Definition File Structure

Base Version (24.4/crypto.yaml)

name: Crypto
path: Cisco-IOS-XR-um-crypto-cfg:crypto
attributes:
  - yang_name: ca
    attributes:
      - yang_name: trustpoint
        tf_name: ca_trustpoints
        type: List
        attributes:
          - yang_name: trustpoint-name
            tf_name: trustpoint_name
            type: String
            id: true
          - yang_name: method/est/credential/certificate
            tf_name: method_est_credential_certificate
            type: String
            example: "CERT1"

Higher Version (25.2/crypto.yaml)

name: Crypto
attributes:
  - yang_name: ca
    attributes:
      - yang_name: trustpoint
        attributes:
          - yang_name: method/est/credential/certificate
            legacy: true  # Field removed in this version
          - yang_name: enrollment/authentication-profile
            tf_name: enrollment_authentication_profile
            type: String
            example: "PROFILE1"

Generated Model Structure

// model_iosxr_crypto.go (unified model for all versions)

type Crypto struct {
    Device       types.String           `tfsdk:"device"`
    Id           types.String           `tfsdk:"id"`
    CaTrustpoints []CryptoCaTrustpoints `tfsdk:"ca_trustpoints"`
}

type CryptoCaTrustpoints struct {
    TrustpointName                     types.String `tfsdk:"trustpoint_name"`
    MethodEstCredentialCertificate     types.String `tfsdk:"method_est_credential_certificate"`
    EnrollmentAuthenticationProfile    types.String `tfsdk:"enrollment_authentication_profile"`
}

// GetVersionConstraints returns version-specific field constraints
func (data Crypto) GetVersionConstraints() []helpers.FieldVersionConstraint {
    return []helpers.FieldVersionConstraint{
        {
            FieldPath:        "ca_trustpoints.method_est_credential_certificate",
            RemovedInVersion: "25.2",  // Removed in 25.2
        },
        {
            FieldPath:      "ca_trustpoints.enrollment_authentication_profile",
            AddedInVersion: "25.2",    // Added in 25.2
        },
    }
}

// GetRangeConstraints returns version-specific integer ranges
func (data Crypto) GetRangeConstraints() []helpers.FieldRangeConstraint {
    // No range constraints for this resource
    return nil
}

Generated Resource Structure

// resource_iosxr_crypto.go (unified resource for all versions)

func (r *CryptoResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
    var plan Crypto
    
    // Read plan
    diags := req.Plan.Get(ctx, &plan)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }
    
    // Validate version compatibility (ONLY GENERATED IF HasVersionDifferences = true)
    if !helpers.Validate(r.data.Version, plan, &resp.Diagnostics) {
        return
    }
    
    // ... rest of create logic
}

Real-World Use Cases

Use Case 1: Performance Measurement with Different Ranges

The endpoint_default_probe_tx_interval field has different valid ranges in different IOS-XR versions:

YANG Model for Version 24.4:

leaf tx-interval {
  type uint32 {
    range "30000..15000000";  // 30 seconds to 15000 seconds
  }
}

YANG Model for Version 25.2:

leaf tx-interval {
  type uint32 {
    range "3300..15000000";   // 3.3 seconds to 15000 seconds
  }
}

Terraform Configuration:

# FAILS for v244 - value below minimum
resource "iosxr_performance_measurement_liveness_profile" "test_v244" {
  provider = iosxr.v244
  profile_name = "PROF-1"
  endpoint_default = true
  endpoint_default_probe_tx_interval = 5000  # ERROR: below 30000
}

# SUCCEEDS for v252 - value within range
resource "iosxr_performance_measurement_liveness_profile" "test_v252" {
  provider = iosxr.v252
  profile_name = "PROF-2"
  endpoint_default = true
  endpoint_default_probe_tx_interval = 5000  # OK: between 3300 and 15000000
}

Use Case 2: Crypto with Version-Specific Fields

Version 24.4 Configuration:

resource "iosxr_crypto" "test_v244" {
  provider = iosxr.v244
  ca_trustpoints = [
    {
      trustpoint_name = "TP1"
      description = "Main trustpoint"
      method_est_credential_certificate = "EST-BOOTSTRAP"  # Available in v244
      # enrollment_authentication_profile NOT available yet
    }
  ]
}

Version 25.2 Configuration:

resource "iosxr_crypto" "test_v252" {
  provider = iosxr.v252
  ca_trustpoints = [
    {
      trustpoint_name = "TP2"
      description = "Main trustpoint"
      # method_est_credential_certificate REMOVED in v252
      enrollment_authentication_profile = "AUTH-PROF-1"  # New field in v252
    }
  ]
}

Use Case 3: Multiple Devices with Different Versions

locals {
  devices = {
    "router1" = {
      host    = "192.168.1.1"
      version = "24.4"  # optional
    }
    "router2" = {
      host    = "192.168.1.2"
      version = "25.2"  # optional
    }
  }
}

provider "iosxr" {
  devices = local.devices
}

# Configure based on device version
resource "iosxr_performance_measurement_liveness_profile" "router1" {
  device = "router1"
  profile_name = "PROF-1"
  endpoint_default = true
  endpoint_default_probe_tx_interval = 30000  # OK for v244
}

resource "iosxr_performance_measurement_liveness_profile" "router2" {
  device = "router2"
  profile_name = "PROF-2"
  endpoint_default = true
  endpoint_default_probe_tx_interval = 5000   # OK for v252 (lower minimum)
}

How to Add Version-Specific Fields

Step 1: Add Field to Higher Version Definition

Create or edit gen/definitions/25.2/resource_name.yaml:

name: Resource Name
attributes:
  - yang_name: some-container
    attributes:
      - yang_name: new-field
        tf_name: new_field
        type: String
        example: "value"
        # No need to specify version - automatically tracked as "added in 25.2"

Step 2: Mark Field as Legacy (Removed)

name: Resource Name
attributes:
  - yang_name: some-container
    attributes:
      - yang_name: old-field
        legacy: true  # Marks field as removed in this version

Step 3: Mark Entire Resource as Legacy

name: Hostname
legacy: true  # Entire resource removed in this version

Step 4: Regenerate

cd /Users/hayibrah/GolandProjects/terraform-provider-iosxr
go generate

The generator will:

  1. Merge definitions from base (24.4) and higher (25.2) versions
  2. Automatically detect added/removed fields
  3. Extract ranges from YANG models
  4. Generate unified models with version constraints
  5. Generate resources with conditional validation
  6. Generate examples with version comments

Benefits

  • ✅ Single provider supports multiple IOS-XR versions with automatic detection
  • ✅ Version-specific validation prevents misconfigurations before device interaction
  • ✅ Zero overhead for resources without version differences

Automatic Version Detection

iosxr_version is optional. If omitted, the provider auto-detects the version from each device via gNMI by querying /Cisco-IOS-XR-cli-cfg:cli and parsing the CLI config header (!! IOS XR Configuration 24.4). Results are cached in-memory (sync.Map) per device for the duration of the Terraform run.

Accepted format: "24.4", "25.2"ParseVersion() in helpers is the single source of truth for validation and conversion to internal format.

Auto-Detection

provider "iosxr" {
  # iosxr_version omitted - auto-detected per device
  devices = [
    { name = "router1", host = "10.1.1.1" },  # detects 24.4
    { name = "router2", host = "10.1.1.2" },  # detects 25.2
  ]
}

Explicit Version

provider "iosxr" {
  iosxr_version = "24.4"  # optional, skips auto-detection
  devices = [{ name = "router1", host = "10.1.1.1" }]
}

Detection Failure

If auto-detection fails, the provider raises an error with guidance to set iosxr_version explicitly. Supported versions: 24.4, 25.2.

Zero Configuration - auto-detected per device
Cached - one gNMI query per device per run, thread-safe
Fresh - re-detected on every terraform plan / terraform apply

@hayibrah hayibrah changed the title multi-version multi-version support Mar 16, 2026
@hayibrah
hayibrah marked this pull request as draft March 16, 2026 16:32
@hayibrah
hayibrah force-pushed the feature/muli-iosxr-version-support branch 3 times, most recently from ce48e57 to 91f61b2 Compare March 17, 2026 02:24
@hayibrah hayibrah changed the title multi-version support Multi-Version Support in Terraform Provider for Cisco IOS-XR Mar 17, 2026
@hayibrah
hayibrah force-pushed the feature/muli-iosxr-version-support branch 2 times, most recently from f4f984c to 8cf4ff3 Compare March 17, 2026 14:29
@hayibrah
hayibrah force-pushed the feature/muli-iosxr-version-support branch from 8cf4ff3 to 63c980f Compare March 17, 2026 14:47
@hayibrah
hayibrah marked this pull request as ready for review March 17, 2026 15:12
@rwcrowe
rwcrowe requested review from danischm and rwcrowe March 19, 2026 15:43
@hayibrah hayibrah changed the title Multi-Version Support in Terraform Provider for Cisco IOS-XR Multi-Version Support in Terraform Provider for Cisco IOS-XR & 25.1X support Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant