How to use `yq` to set a property to a multi-line string?
Asked Answered
S

4

9

I have a certificate file that looks similar to:

-------BEGIN CERTIFICATE-------
asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
-------END CERTIFICATE--------

I also have a YAML file (an OpenShift Template) that looks like this:

apiVersion: v1
kind: Template
objects:
- apiVersion: v1
  kind: Route
  tls:
    certificate:
    key:
  someOther: stuff

How can I use yq to set the value of the property certificate in the YAML file above, to the contents of the certificate file so that the output looks somewhat like this:

apiVersion: v1
...
    certificate: |
      -------BEGIN CERTIFICATE-------
      asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
      qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
      -------END CERTIFICATE--------

Neither an Internet search nor documentation was of any help. The closest I got was using the following:

yq w /tmp/template.yaml objects[0].tls.certificate "\n$(cat cert.pem)"

...which left me with the following output:

certificate: !!binary |
      fC0KLS0tLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0tLQphc2RvcWlqZXBvcWp3ZTFpND
      lpMTIwOTQxcDJqNG9tc2zDYXNkYWpzZMNxd2Vxd2UKcXdlbHFqd2vDYXNkbGFqc8O2bGtq
      YXNsZGtqYWtsanNkbGtqYXNkYXNkcGlxd2UKLS0tLS0tLUVORCBDRVJUSUZJQ0FURS0tLS
      0tLS0t

...which strangely is the base64 encoded variant of what I wanted to add preceded by !!binary |. Any ideas what's going on and how I can achieve desired output instead?

Sudbury answered 2/9, 2019 at 18:19 Comment(1)
Are you still looking for a solution to this problem? In the latest yq release v3 - This works yq w /tmp/template.yaml objects[0].tls.certificate -- "$(< cert.pem)", can you let me know if this works?Oocyte
C
2

I have tested @Inian suggestion with yq3 and it works.

It can also be achieve in yq4 with the following syntax:

template.yml

# template.yml
apiVersion: v1
kind: Template
objects:
  - apiVersion: v1
    kind: Route
    tls:
      certificate:
      key:
    someOther: stuff

cert.pem

-------BEGIN CERTIFICATE-------
asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
-------END CERTIFICATE--------

command

yq eval '.objects[0].tls.certificate = "'"$(< cert.pem)"'"' template.yml

output

apiVersion: v1
kind: Template
objects:
  - apiVersion: v1
    kind: Route
    tls:
      certificate: |-
        -------BEGIN CERTIFICATE-------
        asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
        qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
        -------END CERTIFICATE--------
      key:
    someOther: stuff
Contention answered 13/4, 2021 at 0:32 Comment(1)
Would you know what is the equivalent in yq2?Judaize
P
8

Note that in bash, when you use '$(..)' it will trim trailing newlines (which is why the yaml string block starts with |- instead of |.

To get | (and including the trailing new line) you will need to:

IFS= read -rd '' output < <(cat cert.pem)
output=$output yq e '.objects[0].tls.certificate = strenv(output)' myfile.yml

Disclaimer: I wrote yq

Process answered 5/12, 2021 at 1:12 Comment(2)
You should replace < <(cat cert.pem) with < cert.pemNebraska
yq eval '.objects[0].tld.certificate = load_str("cert.pem")' myfile.yaml works, too. @mike.f, any reason to prefer your variant and/or is there something wrong with mine?Carolinacaroline
C
7

You can use the load_str operator to load a file's contents as a string, and assign it to a property:

yq '.objects[0].tls.certificate = load_str("cert.pem")' template.yaml

(above, template.yaml denotes path to your OpenShift template YAML file, if this wasn't obvious)

The above command will produce the following output in your case:

apiVersion: v1
kind: Template
objects:
  - apiVersion: v1
    kind: Route
    tls:
      certificate: |
        -------BEGIN CERTIFICATE-------
        asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
        qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
        -------END CERTIFICATE--------
      key:
    someOther: stuff
Carolinacaroline answered 23/3, 2023 at 15:39 Comment(0)
C
2

I have tested @Inian suggestion with yq3 and it works.

It can also be achieve in yq4 with the following syntax:

template.yml

# template.yml
apiVersion: v1
kind: Template
objects:
  - apiVersion: v1
    kind: Route
    tls:
      certificate:
      key:
    someOther: stuff

cert.pem

-------BEGIN CERTIFICATE-------
asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
-------END CERTIFICATE--------

command

yq eval '.objects[0].tls.certificate = "'"$(< cert.pem)"'"' template.yml

output

apiVersion: v1
kind: Template
objects:
  - apiVersion: v1
    kind: Route
    tls:
      certificate: |-
        -------BEGIN CERTIFICATE-------
        asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
        qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
        -------END CERTIFICATE--------
      key:
    someOther: stuff
Contention answered 13/4, 2021 at 0:32 Comment(1)
Would you know what is the equivalent in yq2?Judaize
G
0

I might have found a bug @mike.f

#!/usr/bin/env bash

###
# ❯ yq --version
# yq (https://github.com/mikefarah/yq/) version 4.27.5
##

echo "########## Multiline string is set ##########"
cat > cert.pem << EOF
-------BEGIN CERTIFICATE-------
asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
-------END CERTIFICATE--------
EOF

IFS= read -rd '' cert < <(cat cert.pem)
export cert=$cert
yq --null-input '.cert = strenv(cert)'

echo "########## Multiline string is NOT set ##########"
cat > flatcar_ignition.yml << EOF
storage:
  files:
    - path: /opt/k8s_setup.sh
      filesystem: root
      contents:
        inline: ""
      mode: 0744
      user:
        id: 500
      group:
        id: 501
EOF
cat > k8s_setup.sh << EOF
#!/usr/bin/env bash
echo "test1" > /test.txt
echo "test2" >> /test.txt
echo "test3" >> /test.txt
EOF

IFS= read -rd '' k8s_setup < <(cat k8s_setup.sh)
export k8s_setup=$k8s_setup
yq e '.storage.files[0].contents.inline = strenv(k8s_setup)' flatcar_ignition.yml

Results in:

❯ ./test.sh
########## Multiline string is set ##########
cert: |
  -------BEGIN CERTIFICATE-------
  asdoqijepoqjwe1i49i120941p2j4omslasdajsdqweqwe
  qwelqjwkasdlajsölkjasldkjakljsdlkjasdasdpiqwe
  -------END CERTIFICATE--------

########## Multiline string is NOT set ##########
storage:
  files:
    - path: /opt/k8s_setup.sh
      filesystem: root
      contents:
        inline: "#!/usr/bin/env bash\necho \"test1\" > /test.txt\necho \"test2\" >> /test.txt\necho \"test3\" >> /test.txt\n"
      mode: 0744
      user:
        id: 500
      group:
       id: 501
Guitar answered 28/9, 2022 at 16:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.