Search code examples
bashkubernetestrino

Escape single and double quotes in K8s Lifecycle hook


lifecycle:
  preStop:
    exec:
      command: ["sh", "-c", "curl -v  -X PUT -d '\"SHUTTING_DOWN\"'  http://localhost:8080/v1/info/state"]

I am expecting this will produce a curl url like

curl -v  -X PUT -d '"SHUTTING_DOWN"' http://localhost:8080/v1/info/state 

How ever I am getting with extra single quotes surrounded ''"SHUTTING_DOWN"''

curl -v  -X PUT -d ''"SHUTTING_DOWN"'' http://localhost:8080/v1/info/state 

Any pointers, where am I going wrong?


Solution

  • I'd suggest getting rid of as many layers of quotes as you can. In the original example you have a layer of quotes from YAML, plus a layer of quotes from the sh -c wrapper. Since you need the HTTP PUT body itself to have both single and double quotes – you need to send the string '"SHUTTING_DOWN"' with both kinds of quotes over the wire – getting rid of as much quoting as you can is helpful.

    In both the shell and YAML, the two kinds of quotes behave differently. Backslash escaping only works in double-quoted strings and so you probably need that at the outer layer; then you need single quotes inside the double quotes; and then you need backslash-escaped double quotes inside that.

    In YAML specifically the quotes around strings are usually optional, unless they're required to disambiguate things (forcing 'true' or '12345') to be strings. This lets you get rid of one layer of quoting. You also may find this slightly clearer if you use YAML block style with one list item on a line.

    command:
      - /bin/sh
      - -c
      - curl -v -X PUT -d "'\"SHUTTING_DOWN\"'" http://localhost:8080/v1/info/state
    

    I might even go one step further here, though. You're not using environment variable expansion, multiple commands, or anything else that requires a shell. That means you don't need the sh -c wrapper. If you remove this, then the only layer of quoting you need is YAML quoting; you don't need to worry about embedding a shell-escaped string inside a YAML-quoted string.

    You do need to make sure the quotes are handled correctly. If the string begins with a ' or " then YAML will parse it as a quoted string, and if not then there are no escaping options in an unquoted string. So again you probably need to put the whole thing in a double-quoted string and backslash-escape the double quotes that are part of the value.

    Remember that each word needs to go into a separate YAML list item. curl like many commands will let you combine options and arguments, so you can have -XPUT as a single argument or -X and PUT as two separate arguments, but -X PUT as a single word will include the space as part of that word and confuse things.

    command:
      - curl
      - -v
      - -X
      - PUT
      - -d
      - "'\"SHUTTING_DOWN\"'"
      - http://localhost:8080/v1/info/state