** 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

Reply via email to