CiscoDevNet / terraform-provider-iosxe

Terraform Cisco IOS-XE Provider
https://registry.terraform.io/providers/CiscoDevNet/iosxe
Mozilla Public License 2.0
59 stars 22 forks source link

iosxe_restconf code for TACACS Server #169

Open ipeph opened 5 months ago

ipeph commented 5 months ago

Hi I have this JSON result from tacacs API..

{
    "Cisco-IOS-XE-aaa:server": [
        {
            "name": "ISE1",
            "address": {
                "ipv4": "1.1.1.1"
            },
            "key": {
                "encryption": "7",
                "key": "XXX"
            }
        },
        {
            "name": "ISE2",
            "address": {
                "ipv4": "2.2.2.2"
            },
            "key": {
                "encryption": "7",
                "key": "XXX"
            }
        }
    ]
}

How i can translate this code above to use iosxe_restconf, because i want to create another line of ISE config.

I'm using this code below but its failed.

resource "iosxe_restconf" "aaa_server" {
  path = "Cisco-IOS-XE-native:native/tacacs"
  lists = [
    {
      name = "Cisco-IOS-XE-aaa:server"
      key = "name"
      items = [
        {
          name = "ISE3",
          address = jsonencode(
          {"ipv4": "3.3.3.3"}
          ),
          key = jsonencode(
          {"key": {
              "encryption": "7",
              "key": "XXXX"
           }
          }
          )
        }
      ]
    }
  ]
}

Error result :

╷
│ Error: Client Error
│ 
│   with iosxe_restconf.aaa_server,
│   on main.tf line 102, in resource "iosxe_restconf" "aaa_server":
│  102: resource "iosxe_restconf" "aaa_server" {
│ 
│ Failed to configure object (PATCH), got error: HTTP Request failed: StatusCode 400, RESTCONF errors {Error:[{ErrorType:application ErrorTag:malformed-message ErrorAppTag: ErrorPath:/Cisco-IOS-XE-native:native/tacacs ErrorMessage:invalid value for: address in /ios:native/ios:tacacs/ios-aaa:server[ios-aaa:name='ISE3']/ios-aaa:address ErrorInfo:}]} {PatchId:
│ GlobalStatus:{Ok:false Errors:{Error:[]}} EditStatus:{Edit:[]} Errors:{Error:[]}}

Thanks.

jabielecki commented 5 months ago

Hi @ipeph, a question of fact: Does this dedicated resource work with your setup at all?: https://registry.terraform.io/providers/CiscoDevNet/iosxe/latest/docs/resources/tacacs_server

danischm commented 5 months ago

As @jabielecki mentioned, the dedicated resource would be the preferred method of configuration. When using iosxe_restconf there is no need to use jsonencode(), you would address nested elements using a "path" syntax:

resource "iosxe_restconf" "aaa_server" {
  path = "Cisco-IOS-XE-native:native/tacacs"
  lists = [
    {
      name = "Cisco-IOS-XE-aaa:server"
      key = "name"
      items = [
        {
          name = "ISE3"
          "address/ipv4" = "3.3.3.3"
          "key/key" = "ABCDEFG"
        }
      ]
    }
  ]
}
ipeph commented 5 months ago

Hi @ipeph, a question of fact: Does this dedicated resource work with your setup at all?: https://registry.terraform.io/providers/CiscoDevNet/iosxe/latest/docs/resources/tacacs_server

Hi @jabielecki, yes correct i could use that but i had some problem using this resource.

resource "iosxe_tacacs_server" "ISE1" {
  name         = "ISE1"
  address_ipv4 = "1.1.1.1"
  key          = "XXXXXXX"
}

resource "iosxe_tacacs_server" "ISE2" {
  name         = "ISE2"
  address_ipv4 = "2.2.2.2"
  key          = "XXXXXXX"
}

Output

  # iosxe_tacacs_server.APDC3 will be updated in-place
  ~ resource "iosxe_tacacs_server" "ISE1" {
        id           = "Cisco-IOS-XE-native:native/tacacs/Cisco-IOS-XE-aaa:server=ISE1"
      ~ key          = "153B2F41061B3E2C0667132B170D1514" -> "XXXXXXX"
        name         = "ISE1"
        # (1 unchanged attribute hidden)
    }

  # iosxe_tacacs_server.APDC4 will be updated in-place
  ~ resource "iosxe_tacacs_server" "ISE2" {
        id           = "Cisco-IOS-XE-native:native/tacacs/Cisco-IOS-XE-aaa:server=ISE2"
      ~ key          = "10672D540726070322500C2220223022" -> "XXXXXXX"
        name         = "ISE2"
        # (1 unchanged attribute hidden)
    }

╷
│ Error: Client Error
│ 
│   with iosxe_tacacs_server.ISE1,
│   on main.tf line 127, in resource "iosxe_tacacs_server" "ISE1":
│  127: resource "iosxe_tacacs_server" "ISE1" {
│ 
│ Failed to configure object (PATCH), got error: HTTP Request failed: StatusCode 400, RESTCONF errors {Error:[{ErrorType:application ErrorTag:invalid-value ErrorAppTag: ErrorPath:/Cisco-IOS-XE-native:native/tacacs/Cisco-IOS-XE-aaa:server ErrorMessage:inconsistent value: Device refused one or more commands ErrorInfo:}]}
│ {PatchId: GlobalStatus:{Ok:false Errors:{Error:[]}} EditStatus:{Edit:[]} Errors:{Error:[]}}
╵
╷
│ Error: Client Error
│ 
│   with iosxe_tacacs_server.ISE2,
│   on main.tf line 133, in resource "iosxe_tacacs_server" "ISE2":
│  133: resource "iosxe_tacacs_server" "ISE2" {
│ 
│ Failed to configure object (PATCH), got error: HTTP Request failed: StatusCode 400, RESTCONF errors {Error:[{ErrorType:application ErrorTag:invalid-value ErrorAppTag: ErrorPath:/Cisco-IOS-XE-native:native/tacacs/Cisco-IOS-XE-aaa:server ErrorMessage:inconsistent value: Device refused one or more commands ErrorInfo:}]}
│ {PatchId: GlobalStatus:{Ok:false Errors:{Error:[]}} EditStatus:{Edit:[]} Errors:{Error:[]}}

Sometimes the state is not sync because terraform sometimes read the encypted value of tacacs so i though i could use the iosxe_restconf resource directly.

ipeph commented 5 months ago

As @jabielecki mentioned, the dedicated resource would be the preferred method of configuration. When using iosxe_restconf there is no need to use jsonencode(), you would address nested elements using a "path" syntax:

resource "iosxe_restconf" "aaa_server" {
  path = "Cisco-IOS-XE-native:native/tacacs"
  lists = [
    {
      name = "Cisco-IOS-XE-aaa:server"
      key = "name"
      items = [
        {
          name = "ISE3"
          "address/ipv4" = "3.3.3.3"
          "key/key" = "ABCDEFG"
        }
      ]
    }
  ]
}

Hi @danischm,

Thanks this is work perfectly like charm. And i have some request if its ok with you, this example is not listed on the documentation, maybe if this example can be added on the documentation.

Thanks.

ipeph commented 5 months ago

Hi @danischm,

I have another question. I have this API result from this URL.

https://{{host}}:{{port}}/restconf/data/Cisco-IOS-XE-native:native/aaa/authenticaiton

{
    "Cisco-IOS-XE-aaa:authentication": {
        "attempts": {
            "login": 4
        },
        "enable": {
            "default": {
                "group": "tacacs+",
                "enable": [
                    null
                ]
            }
        },
        "login": [
            {
                "name": "default",
                "a1": {
                    "local": [
                        null
                    ]
                },
                "a2": {
                    "group": "tacacs+"
                }
            }
        ]
    }
}

How i can translate this into correct terraform code ?

I tried this 2 code below, and having an error after applying the code. 1st code

resource "iosxe_restconf" "aaa_authentication" {
  path = "Cisco-IOS-XE-native:native/aaa/authentication"
  attributes = {
    "attempts/login" = 4
    "enable/default/group"  = "tacacs+"
    "enable/default/enable" = null
    "login/name"            = "default"
    "login/a1/local"        = null
    "login/a2/group"        = "tacacs+"
  }
}

output:

Plan: 1 to add, 0 to change, 0 to destroy.
iosxe_restconf.aaa_authentication: Creating...
╷
│ Error: Client Error
│ 
│   with iosxe_restconf.aaa_authentication,
│   on main.tf line 175, in resource "iosxe_restconf" "aaa_authentication":
│  175: resource "iosxe_restconf" "aaa_authentication" {
│ 
│ Failed to configure object (PATCH), got error: HTTP Request failed: StatusCode 400, RESTCONF errors {Error:[{ErrorType:application ErrorTag:malformed-message ErrorAppTag: ErrorPath:/Cisco-IOS-XE-native:native/aaa/Cisco-IOS-XE-aaa:authentication ErrorMessage:0: Internal error ErrorInfo:}]} {PatchId: GlobalStatus:{Ok:false Errors:{Error:[]}}
│ EditStatus:{Edit:[]} Errors:{Error:[]}}
╵

2nd code

resource "iosxe_restconf" "aaa_authentication" {
  path = "Cisco-IOS-XE-native:native/aaa/authentication"
  lists = [
    {
      name = "Cisco-IOS-XE-aaa:authentication"
      key = "login"
      items = [
        {
          "attempts/login" = 4
          "enable/default/group"  = "tacacs+"
          "enable/default/enable" = null
          "login/name"            = "default"
          "login/a1/local"        = null
          "login/a2/group"        = "tacacs+"
        }
      ]
    }
  ]
}

output

iosxe_restconf.aaa_authentication: Creating...
╷
│ Error: Client Error
│ 
│   with iosxe_restconf.aaa_authentication,
│   on main.tf line 187, in resource "iosxe_restconf" "aaa_authentication":
│  187: resource "iosxe_restconf" "aaa_authentication" {
│ 
│ Failed to configure object (PATCH), got error: HTTP Request failed: StatusCode 400, RESTCONF errors {Error:[{ErrorType:application ErrorTag:malformed-message ErrorAppTag: ErrorPath:/Cisco-IOS-XE-native:native/aaa/Cisco-IOS-XE-aaa:authentication ErrorMessage:0: Internal error ErrorInfo:}]} {PatchId: GlobalStatus:{Ok:false Errors:{Error:[]}}
│ EditStatus:{Edit:[]} Errors:{Error:[]}}