** Description changed: + [Impact] + + When a vendor data json provides a dictionary without a 'cloud-init' + key, cloud-init renders a non functional user-data, so any configuration + (i.e. ssh public keys to use) is missed. + + This prevents cloud providers from publishing a vendor data that is not + intended to be consumed by cloud-init. + + This patch checks for the existence of 'cloud-init' key and tries to get + None, a string or a list as value, if this process fails or cloud-init + key is missing the vendor data is set to None. + + [Test Case] + + * deploy an OpenStack cloud (easy right? :) ) + - the easiest way is to branch https://code.launchpad.net/~ost-maintainers/openstack-charm-testing/trunk and run: juju deployer -c default.yaml -d -v -s 10 trusty-kilo + * configure vendor data + - Edit /etc/nova/nova.conf in neutron-gateway unit(s), include the following two lines: + vendordata_driver=nova.api.metadata.vendordata_json.JsonFileVendorData + vendordata_jsonfile_path=/etc/nova/vendordata.json + - Create /etc/nova/vendordata.json in neutron-gateway unit(s) with the following content: + {"custom": {"a": 1, "b": [2, 3]}} + - Restart nova-api-metadata (sudo service nova-api-metadata restart) + * Launch an instance using trusty + + Expected result: + - the new instance is launched and is accesible according to the configuration used + + Actual result: + - cloud-init fails to configure the ssh public key + + [Regression Potential] + + * This patch is already part of Vivid and there are no known issues. + * This proposed fix was tested with a custom image and no issues were detected. + + [Other Info] + I encountered this issue when adding custom vendor data via nova- compute. Originally the bug manifested as SSH host key generation failing to fire when vendor data was present (example vendor data below). {"msg": "", "uuid": "4996e2b67d2941818646481453de1efe", "users": [{"username": "erhudy", "sshPublicKeys": [], "uuid": "erhudy"}], "name": "TestTenant"} I launched a volume-backed instance, waited for it to fail, then terminated it and mounted its root volume to examine the logs. What I found was that cloud-init was failing to process vendor-data into MIME multipart (note the absence of the line that indicates that cloud-init is writing vendor-data.txt.i): 2015-06-25 21:41:02,178 - util.py[DEBUG]: Writing to /var/lib/cloud/instance/obj.pkl - wb: [256] 9751 bytes 2015-06-25 21:41:02,178 - util.py[DEBUG]: Writing to /var/lib/cloud/instances/65c9fb0c-0700-4f87-a22f-c59534e98dfb/user-data.txt - wb: [384] 0 bytes 2015-06-25 21:41:02,184 - util.py[DEBUG]: Writing to /var/lib/cloud/instances/65c9fb0c-0700-4f87-a22f-c59534e98dfb/user-data.txt.i - wb: [384] 345 bytes 2015-06-25 21:41:02,185 - util.py[DEBUG]: Writing to /var/lib/cloud/instances/65c9fb0c-0700-4f87-a22f-c59534e98dfb/vendor-data.txt - wb: [384] 234 bytes 2015-06-25 21:41:02,185 - util.py[DEBUG]: Reading from /proc/uptime (quiet=False) After following the call chain all the way down, I found the problematic code in user_data.py: # Coverts a raw string into a mime message def convert_string(raw_data, headers=None): - if not raw_data: - raw_data = '' - if not headers: - headers = {} - data = util.decomp_gzip(raw_data) - if "mime-version:" in data[0:4096].lower(): - msg = email.message_from_string(data) - for (key, val) in headers.iteritems(): - _replace_header(msg, key, val) - else: - mtype = headers.get(CONTENT_TYPE, NOT_MULTIPART_TYPE) - maintype, subtype = mtype.split("/", 1) - msg = MIMEBase(maintype, subtype, *headers) - msg.set_payload(data) - return msg + if not raw_data: + raw_data = '' + if not headers: + headers = {} + data = util.decomp_gzip(raw_data) + if "mime-version:" in data[0:4096].lower(): + msg = email.message_from_string(data) + for (key, val) in headers.iteritems(): + _replace_header(msg, key, val) + else: + mtype = headers.get(CONTENT_TYPE, NOT_MULTIPART_TYPE) + maintype, subtype = mtype.split("/", 1) + msg = MIMEBase(maintype, subtype, *headers) + msg.set_payload(data) + return msg raw_data in the case that is failing is a dictionary rather than the expected string, so slicing into data causes a TypeError: unhashable type exception. I think this bug was fixed after a fashion in 0.7.7, where the call to util.decomp_gzip() is now wrapped by util.decode_binary(), which appears to always return a string.
** Summary changed: - Custom vendor data causes cloud-init failure on 0.7.5 + [SRU] Custom vendor data causes cloud-init failure on 0.7.5 ** Patch added: "lp1469260_trusty.debdiff" https://bugs.launchpad.net/cloud-init/+bug/1469260/+attachment/4434870/+files/lp1469260_trusty.debdiff ** Changed in: cloud-init (Ubuntu Trusty) Status: New => In Progress -- You received this bug notification because you are a member of Ubuntu Server Team, which is subscribed to cloud-init in Ubuntu. https://bugs.launchpad.net/bugs/1469260 Title: [SRU] Custom vendor data causes cloud-init failure on 0.7.5 To manage notifications about this bug go to: https://bugs.launchpad.net/cloud-init/+bug/1469260/+subscriptions -- Ubuntu-server-bugs mailing list Ubuntu-server-bugs@lists.ubuntu.com Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/ubuntu-server-bugs