[Bug 1469260] Re: Custom vendor data causes cloud-init failure on 0.7.5
Felipe Reyes
1469260 at bugs.launchpad.net
Tue Jul 28 03:18:29 UTC 2015
** 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
Sponsors Team, which is subscribed to the bug report.
https://bugs.launchpad.net/bugs/1469260
Title:
[SRU] Custom vendor data causes cloud-init failure on 0.7.5
Status in cloud-init:
Fix Released
Status in cloud-init package in Ubuntu:
Fix Released
Status in cloud-init source package in Trusty:
In Progress
Status in cloud-init source package in Utopic:
Invalid
Bug description:
[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
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.
To manage notifications about this bug go to:
https://bugs.launchpad.net/cloud-init/+bug/1469260/+subscriptions
More information about the Ubuntu-sponsors
mailing list