DealerDotCom / terraform-provider-bigip

Terraform provider for F5 BigIP
Mozilla Public License 2.0
32 stars 19 forks source link

Unable to escape "&" character in tf json file. #40

Open kkloos1 opened 7 years ago

kkloos1 commented 7 years ago

I'm attempting to setup an HTTP monitor that includes a query string in the request, however I couldn't find anything on Terraform's configuration syntax page, https://www.terraform.io/docs/configuration/syntax.htm, documenting how to use escape characters in these files.

Tried to use the typical backslash "\" character in front of the "&" character as well as the UTF-8 escape sequence "\u0026" for the ampersand character in the setup file but both threw exceptions. Here is an example of the GET request I want to execute against the remote web server:

GET /test?x=1&y=2 HTTP/1.1\nHost: example.com \nConnection: close\n\n\r\n

And here are the configuration examples I used in my Terraform config file as well as the error that gets thrown by Terraform when I try applying the changes:

"resource": {
    "bigip_ltm_monitor": {
        "TEST-HTTP-MONITOR-80": {
            "name": "/Common/TEST-HTTP-MONITOR-80",
            "parent": "/Common/http",
            "send": "GET /test?x=1\&y=2 HTTP/1.1\\nHost: example.com \\nConnection: close\\n\\n\\r\\n",
            "receive": "UP",
            "timeout": "16",
            "interval": "5"
        }
    }
}

.\terraform.exe apply
Error loading config: Error parsing C:\Test\Terraform\Terraform-BIGIP\Terraform-BIGIP\BIG-IP_Test.tf.json: 23:34: illegal char escape

"resource": {
    "bigip_ltm_monitor": {
        "TEST-HTTP-MONITOR-80": {
            "name": "/Common/TEST-HTTP-MONITOR-80",
            "parent": "/Common/http",
            "send": "GET /test?x=1\u0026y=2 HTTP/1.1\\nHost: example.com \\nConnection: close\\n\\n\\r\\n",
            "receive": "UP",
            "timeout": "16",
            "interval": "5"
        }
    }
}

bigip_ltm_monitor.TEST-HTTP-MONITOR-80: Modifying...
  send: "GET /test?x=1y=2 HTTP/1.1\\nHost: example.com \\nConnection: close\\n\\n\\r\\n" => "GET /test?x=1&y=2 HTTP/1.1\\nHost: example.sentry.com \\nConnection: close\\n\\n\\r\\n"
Error applying plan:

1 error(s) occurred:

* bigip_ltm_monitor.TEST-HTTP-MONITOR-80: double quotes are not balanced

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

When I remove the "&" character from the send field and leave everything else the same terraform is able to create/update the monitor without any issues.

aburnett commented 7 years ago

Maybe this is a dumb question but why do you need to escape the & in the first place?

"send": "GET /test?x=1&y=2....

kkloos1 commented 7 years ago

When I just try entering the & character by itself I get the following "double quotes are not balanced" exception

.\terraform.exe apply
bigip_ltm_monitor.TEST-HTTP-MONITOR-80: Modifying...
  send: "GET /test?x=1y=2 HTTP/1.1\\nHost: example.com \\nConnection: close\\n\\n\\r\\n" => "GET /test?x=1&y=2 HTTP/1.1\\nHost: example.com \\nConnection: close\\n\\n\\r\\n"
bigip_ltm_monitor.TEST-HTTPS-MONITOR-443: Modifying...
  send: "GET /test?x=1y=2 HTTP/1.1\\nHost: example.com \\nConnection: close\\n\\n\\r\\n" => "GET /test?x=1&y=2 HTTP/1.1\\nHost: example.com \\nConnEercrtoiro an:p pcllyoisneg\ \pnl\a\nn:\
\r
\\n2"
error(s) occurred:

* bigip_ltm_monitor.TEST-HTTPS-MONITOR-443: double quotes are not balanced
* bigip_ltm_monitor.TEST-HTTP-MONITOR-80: double quotes are not balanced

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

The weird formatting in the second LTM monitor output at the end appears to have an "Error applying plan" error message embedded in the output.

Just to give a little more background on what it is I'm trying to accomplish, I have a custom status page configured on the backend web server that will verify connectivity to that host and run some server-side processes to confirm all of it's dependencies ( db's, remote web services, etc.. ) are available. If all is well it'll return an "UP" string in the response which the LTM monitor will look for to determine if the pool member should be enabled/disabled. We're using the URL query string to pass in additional arguments to the page, the "&" character is used as a separator between the different key:value pairs being sent in the request, so in my example we'd have two parameters being sent: x=1 y=2

Could be wrong but it appears from what I'm seeing that the "&" character has some sort of significance in these Terraform configurations and as such it's being processed as a special character instead of just raw character data.

aburnett commented 7 years ago

This looks like it's an error coming from the F5 itself. The & wouldn't have any meaning in the HCL itself. I found this post mentioning similar behavior but with the '?' being the culprit. One thing to keep in mind is that the REST API for the F5 is really just a wrapper around the tmsh commands. So it's likely that any weirdness in tmsh land would translate up the stack.

What if you create your monitor manually then request it through the F5 REST API. Does the request string have any special escaping around the '?' or '&' characters? Might be that the plugin needs to do some extra data munging before submitting the request to the F5.

kkloos1 commented 7 years ago

Not quite sure if this is what you were asking for, I created the monitor using both the local tmsh console and the REST API, here are the results.

tmsh:

    # tmsh create ltm monitor http TEST1-HTTP-MONITOR-80 { send "GET /test?x=1&y=2 HTTP/1.1\\nHost: example.com \\nConnection: close \\n\\n\\r\\n" recv 'UP' recv-disable 'DOWN' timeout 16 interval 5}
    # tmsh list ltm monitor http TEST1-HTTP-MONITOR-80
    ltm monitor http TEST1-HTTP-MONITOR-80 {
        adaptive disabled
        defaults-from http
        destination *:*
        interval 5
        ip-dscp 0
        recv UP
        recv-disable DOWN
        send "GET /test?x=1&y=2 HTTP/1.1\nHost: example.com \nConnection: close \n\n\r\n"
        time-until-up 0
        timeout 16
    }

REST API:

    # tmsh delete ltm monitor http TEST1-HTTP-MONITOR-80
    # cat monitor.json
    {
            "name":"TEST1-HTTP-MONITOR-80",
            "send":"GET /test?x=1&y=2 HTTP/1.1\\nHost: example.com \\nConnection: close \\n\\n\\r\\n",
            "recv":"UP",
            "recv-disable":"DOWN",
            "timeout":"16",
            "interval":"5"
    }
    # curl -k -u admin -H "Content-Type: application/json" -X POST --data-binary @monitor.json https://f5host.com/mgmt/tm/ltm/monitor/http
    {
        "kind":"tm:ltm:monitor:http:httpstate",
        "name":"TEST1-HTTP-MONITOR-80",
        "fullPath":"TEST1-HTTP-MONITOR-80",
        "generation":0,
        "selfLink":"https://localhost/mgmt/tm/ltm/monitor/http/TEST1-HTTP-MONITOR-80?ver=11.6.0",
        "adaptive":"disabled",
        "adaptiveDivergenceType":"relative",
        "adaptiveDivergenceValue":25,
        "adaptiveLimit":200,
        "adaptiveSamplingTimespan":300,
        "defaultsFrom":"/Common/http",
        "destination":"*:*",
        "interval":5,
        "ipDscp":0,
        "manualResume":"disabled",
        "recv":"UP",
        "recvDisable":"DOWN",
        "reverse":"disabled",
        "send":"GET /test?x=1&y=2 HTTP/1.1\\nHost: example.com \\nConnection: close \\n\\n\\r\\n",
        "timeUntilUp":0,
        "timeout":16,
        "transparent":"disabled",
        "upInterval":0
    }

Using both methods I didn't receive any errors, the monitor was successfully created and the send string was properly formatted.

aburnett commented 7 years ago

Great thanks for verifying. I'm still thinking this error is coming back from the F5 API call. If it were a syntax error in the HCL it would get reported before trying to actually apply any changes specified in the terraform config.

The only thing I can think to try next is to uncomment the the Println call in APICall in the go-bigip module to see what the plugin is actually sending to the API. Maybe something funky is going on there. I don't have access to an F5 anymore so I'm sorry I can't be more help.

baxter19 commented 7 years ago

If am following this discussion correctly I believe the issue is in the core big-ip go library, not the provider implementation. See https://github.com/scottdware/go-bigip/issues/22

jakauppila commented 7 years ago

FYI, I submitted https://github.com/scottdware/go-bigip/pull/37 which creates a special encoder so that <, >, and & do not get encoded when being marshaled.