Sorry for whatever stupid thing I’m doing, but I can’t get cloud-init to 
correctly ingest user-data, for example when trying to do cloud-init query

Environment

cloud-init 19.4 (also affects 20.4?)
Amazon EC2
CentOS 7 (+CentOS 8)
More specifically, when I try to cloud-init query... (or access the same in a 
custom Jinja template) on the user data, it fails with

File "/usr/lib/python<ver>/site-packages/cloudinit/cmd/query.py", line 141, in 
handle_args
    response = response[var]
TypeError: string indices must be integers
I went digging into the cloud-init code, because this didn’t make any sense. 
We’re using 19.4 (because CentOS 7), but I hit the same thing with 20.4 on a 
test CentOS 8 box.

The top of the yaml doc looks like

#cloud-config

# 
https://cloudinit.readthedocs.io/en/latest/topics/examples.html#install-and-run-chef-recipes

chef:
  node_name: null
  exec: false   # don't run by default, terraform will set this
  omnibus_url: https://omnitruck.cinc.sh/install.sh
...
The YAML is a valid doc, not binary (file says ASCII text) It begins with 
#cloud-config etc. It doesn’t matter if I explicitly use query -u, or allow the 
engine to pick up the copy in /var/lib/cloud/instance/user-data.txt.

YAML - As far as I can tell, cloud-init is ingesting the user-data file as a 
single block of plain text beginning with chef..., rather than parsing it as 
yaml.

JSON - I used yq to convert the yaml to JSON, but the result was the same - 
cloud-init decided it was a giant block of text instead of converting it to a 
dictionary.

This is what causes the TypeError above. userdata is a dict as it should be, 
but the value of userdata is a string, not a dict. cloud-init tries to treat it 
like a dict as it iterates the dot path to the desired key, ie 
userdata.chef.exec.

There’s a couple of things about this ingestion that are confusing me. It 
doesn’t seem to have any issue with the AWS supplied metadata. query.py appears 
to expect the user-data(?) to be json.

L137: instance_json = util.load_file(instance_data_fn)
L145: instance_data = util.load_json(instance_json)
More than a mere naming convention, load_json in util.py tries to do exactly 
that. Weirder still, it looks like it is assuming the user data content is a 
binary blob that needs to be decoded.

L1507: def load_json(text, root_types=(dict,)):
L1508:   decoded = json.loads(decode_binary(text))
Other aspects of cloud-init seem to handle the supplied user-data. write_files 
(not shown above) acts as expected, and the stock cc_chef Jinja template 
renders values from user-data.

Again, my apologies if I’m doing something dumb. I thought I did, but I 
obviously don’t understand what type of data cloud-init is expecting here.

TIA
-- 
Mailing list: https://launchpad.net/~cloud-init
Post to     : cloud-init@lists.launchpad.net
Unsubscribe : https://launchpad.net/~cloud-init
More help   : https://help.launchpad.net/ListHelp

Reply via email to