diff -Nru cloud-init-0.6.3/debian/changelog cloud-init-0.6.3/debian/changelog --- cloud-init-0.6.3/debian/changelog 2015-02-19 16:46:09.000000000 +0000 +++ cloud-init-0.6.3/debian/changelog 2015-02-27 16:31:08.000000000 +0000 @@ -1,3 +1,9 @@ +cloud-init (0.6.3-0ubuntu1.17) precise; urgency=medium + + * Backport support for fetching passwords in CloudStack (LP: #1422388). + + -- Daniel Watkins Fri, 27 Feb 2015 16:30:27 +0000 + cloud-init (0.6.3-0ubuntu1.16) precise-proposed; urgency=medium [ Ben Howard ] diff -Nru cloud-init-0.6.3/debian/patches/lp-1422388-cloudstack-passwords.patch cloud-init-0.6.3/debian/patches/lp-1422388-cloudstack-passwords.patch --- cloud-init-0.6.3/debian/patches/lp-1422388-cloudstack-passwords.patch 1970-01-01 01:00:00.000000000 +0100 +++ cloud-init-0.6.3/debian/patches/lp-1422388-cloudstack-passwords.patch 2015-02-27 16:29:54.000000000 +0000 @@ -0,0 +1,110 @@ +Description: Backport CloudStack password support. +Author: Daniel Watkins +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1422388 +Last-Update: 2015-02-25 + +--- a/cloudinit/DataSourceCloudStack.py ++++ b/cloudinit/DataSourceCloudStack.py +@@ -28,6 +28,56 @@ + import boto.utils as boto_utils + from struct import pack + ++import httplib as http_client ++ ++ ++class CloudStackPasswordServerClient(object): ++ """ ++ Implements password fetching from the CloudStack password server. ++ ++ http://cloudstack-administration.readthedocs.org/en/latest/templates.html#adding-password-management-to-your-templates ++ has documentation about the system. This implementation is following that ++ found at ++ https://github.com/shankerbalan/cloudstack-scripts/blob/master/cloud-set-guest-password-debian ++ ++ The CloudStack password server is, essentially, a broken HTTP ++ server. It requires us to provide a valid HTTP request (including a ++ DomU_Request header, which is the meat of the request), but just ++ writes the text of its response on to the socket, without a status ++ line or any HTTP headers. This makes HTTP libraries sad, which ++ explains the screwiness of the implementation of this class. ++ ++ This should be fixed in CloudStack by commit ++ a72f14ea9cb832faaac946b3cf9f56856b50142a in December 2014. ++ """ ++ ++ def __init__(self, virtual_router_address): ++ self.virtual_router_address = virtual_router_address ++ ++ def _do_request(self, domu_request): ++ # We have to provide a valid HTTP request, but a valid HTTP ++ # response is not returned. This means that getresponse() chokes, ++ # so we use the socket directly to read off the response. ++ # Because we're reading off the socket directly, we can't re-use the ++ # connection. ++ conn = http_client.HTTPConnection(self.virtual_router_address, 8080) ++ try: ++ conn.request('GET', '', headers={'DomU_Request': domu_request}) ++ conn.sock.settimeout(30) ++ output = conn.sock.recv(1024).decode('utf-8').strip() ++ finally: ++ conn.close() ++ return output ++ ++ def get_password(self): ++ password = self._do_request('send_my_password') ++ if password in ['', 'saved_password']: ++ return None ++ if password == 'bad_request': ++ raise RuntimeError('Error when attempting to fetch root password.') ++ self._do_request('saved_password') ++ return password ++ + + class DataSourceCloudStack(DataSource.DataSource): + api_ver = 'latest' +@@ -38,7 +88,11 @@ + DataSource.DataSource.__init__(self, sys_cfg) + # Cloudstack has its metadata/userdata URLs located at + # http:///latest/ +- self.metadata_address = "http://%s/" % self.get_default_gateway() ++ self.vr_addr = self.get_default_gateway() ++ if not self.vr_addr: ++ raise RuntimeError("No virtual router found!") ++ self.metadata_address = "http://%s/" % (self.vr_addr,) ++ self.cfg = {} + + def get_default_gateway(self): + """ Returns the default gateway ip address in the dotted format +@@ -55,6 +109,9 @@ + def __str__(self): + return "DataSourceCloudStack" + ++ def get_config_obj(self): ++ return self.cfg ++ + def get_data(self): + seedret = {} + if util.read_optional_seed(seedret, base=self.seeddir + "/"): +@@ -71,6 +128,22 @@ + self.metadata_address) + log.debug("crawl of metadata service took %ds" % + (time.time() - start)) ++ password_client = CloudStackPasswordServerClient(self.vr_addr) ++ try: ++ set_password = password_client.get_password() ++ except Exception: ++ util.logexc(LOG, ++ 'Failed to fetch password from virtual router %s', ++ self.vr_addr) ++ else: ++ if set_password: ++ self.cfg = { ++ 'ssh_pwauth': True, ++ 'password': set_password, ++ 'chpasswd': { ++ 'expire': False, ++ }, ++ } + return True + except Exception as e: + log.exception(e) diff -Nru cloud-init-0.6.3/debian/patches/series cloud-init-0.6.3/debian/patches/series --- cloud-init-0.6.3/debian/patches/series 2015-02-19 16:30:38.000000000 +0000 +++ cloud-init-0.6.3/debian/patches/series 2015-02-27 16:31:31.000000000 +0000 @@ -27,3 +27,4 @@ lp-1378441-backport-gce-data-source.patch lp-1383794-gce-short_name.patch lp-1404311-gce-data_encoding.patch +lp-1422388-cloudstack-passwords.patch