diff options
author | Daniel Watkins <daniel.watkins@canonical.com> | 2015-02-20 10:57:18 +0000 |
---|---|---|
committer | Daniel Watkins <daniel.watkins@canonical.com> | 2015-02-20 10:57:18 +0000 |
commit | f8d9ebbe3743bcada75bc1a980b49f493e2da2f1 (patch) | |
tree | 565a4c965b96d5fc3733fa87ed2c1929683580e8 | |
parent | b57c6a109491f344fa6e6fc2593ab2e60ca65249 (diff) | |
download | vyos-cloud-init-f8d9ebbe3743bcada75bc1a980b49f493e2da2f1.tar.gz vyos-cloud-init-f8d9ebbe3743bcada75bc1a980b49f493e2da2f1.zip |
Split CloudStack password handling out to separate class.
-rw-r--r-- | cloudinit/sources/DataSourceCloudStack.py | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py index 85f20c23..0c3c51c0 100644 --- a/cloudinit/sources/DataSourceCloudStack.py +++ b/cloudinit/sources/DataSourceCloudStack.py @@ -39,6 +39,49 @@ from cloudinit import sources, util LOG = logging.getLogger(__name__) +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. + """ + + 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) + conn.request('GET', '', headers={'DomU_Request': domu_request}) + conn.sock.settimeout(30) + output = conn.sock.recv(1024).decode('utf-8').strip() + 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(sources.DataSource): def __init__(self, sys_cfg, distro, paths): sources.DataSource.__init__(self, sys_cfg, distro, paths) @@ -115,8 +158,9 @@ class DataSourceCloudStack(sources.DataSource): self.metadata_address) LOG.debug("Crawl of metadata service took %s seconds", int(time.time() - start_time)) + password_client = CloudStackPasswordServerClient(self.vr_addr) try: - set_password = self.get_password() + set_password = password_client.get_password() except Exception: util.logexc(LOG, 'Failed to fetch password from virtual router %s', @@ -136,25 +180,6 @@ class DataSourceCloudStack(sources.DataSource): self.metadata_address) return False - def get_password(self): - def _do_request(req_string): - # 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 password. - conn = http_client.HTTPConnection(self.vr_addr, 8080) - conn.request('GET', '', headers={'DomU_Request': req_string}) - conn.sock.settimeout(30) - output = conn.sock.recv(1024).decode('utf-8').strip() - conn.close() - return output - password = _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.') - _do_request('saved_password') - return password - def get_instance_id(self): return self.metadata['instance-id'] |