commit google-daemon for openSUSE:Factory
Hello community, here is the log from the commit of package google-daemon for openSUSE:Factory checked in at 2016-02-05 00:32:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/google-daemon (Old) and /work/SRC/openSUSE:Factory/.google-daemon.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "google-daemon" Changes: -------- --- /work/SRC/openSUSE:Factory/google-daemon/google-daemon.changes 2015-12-03 13:31:58.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.google-daemon.new/google-daemon.changes 2016-02-05 00:32:18.000000000 +0100 @@ -1,0 +2,9 @@ +Thu Jan 28 00:03:50 UTC 2016 - rjschwei@suse.com + +- Update to version 1.3.1 (bsc#963879,bsc#963880) + + Refactored accounts daemon. + + Support "ssh-keys" in project metadata in addition to "sshKeys". + + Support instance "override-ssh-keys" in addition to "sshKeys" + + Support "additional-ssh-keys" in instance metadata. + +------------------------------------------------------------------- Old: ---- google-daemon-1.2.10.tar.bz2 New: ---- google-daemon-1.3.1.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ google-daemon.spec ++++++ --- /var/tmp/diff_new_pack.hmMFjT/_old 2016-02-05 00:32:19.000000000 +0100 +++ /var/tmp/diff_new_pack.hmMFjT/_new 2016-02-05 00:32:19.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package google-daemon # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: google-daemon -Version: 1.2.10 +Version: 1.3.1 Release: 0 Summary: VM management inside GCE License: Apache-2.0 ++++++ google-daemon-1.2.10.tar.bz2 -> google-daemon-1.3.1.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-daemon-1.2.10/usr/share/google/google_daemon/accounts_manager.py new/google-daemon-1.3.1/usr/share/google/google_daemon/accounts_manager.py --- old/google-daemon-1.2.10/usr/share/google/google_daemon/accounts_manager.py 2015-09-24 21:47:38.000000000 +0200 +++ new/google-daemon-1.3.1/usr/share/google/google_daemon/accounts_manager.py 2016-01-20 19:41:29.000000000 +0100 @@ -14,7 +14,6 @@ """Main driver logic for managing accounts on GCE instances.""" -import json import logging import os import pwd @@ -55,35 +54,30 @@ reader, writer = os.pipe() # these are file descriptors, not file objects pid = os.fork() if pid: - # we are the parent + # We are the parent. os.close(writer) - reader = os.fdopen(reader) # turn r into a file object - json_tags = reader.read() - if json_tags: - etags = json.loads(json_tags) - if etags: - self.desired_accounts.attributes_etag = etags[0] - self.desired_accounts.instance_sshkeys_etag = etags[1] + reader = os.fdopen(reader) # turn reader into a file object + etag = reader.read() + if etag: + self.desired_accounts.etag = etag reader.close() - logging.debug('New etag: %s', self.desired_accounts.attributes_etag) + logging.debug('New etag: %s', self.desired_accounts.etag) os.waitpid(pid, 0) else: - # we are the child + # We are the child. os.close(reader) writer = os.fdopen(writer, 'w') try: self.RegenerateKeysAndUpdateAccounts() except Exception as e: logging.warning('error while trying to update accounts: %s', e) - # An error happened while trying to update the accounts. Lets sleep a - # bit to avoid getting stuck in a loop for intermittent errors. + # An error happened while trying to update the accounts. + # Sleep for five seconds before trying again. time.sleep(5) - # Write the etag to pass to parent - json_tags = json.dumps( - [self.desired_accounts.attributes_etag, - self.desired_accounts.instance_sshkeys_etag]) - writer.write(json_tags) + # Write the etag to pass to parent. + etag = self.desired_accounts.etag or '' + writer.write(etag) writer.close() # The use of os._exit here is recommended for subprocesses spawned diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-daemon-1.2.10/usr/share/google/google_daemon/desired_accounts.py new/google-daemon-1.3.1/usr/share/google/google_daemon/desired_accounts.py --- old/google-daemon-1.2.10/usr/share/google/google_daemon/desired_accounts.py 2015-09-24 21:47:38.000000000 +0200 +++ new/google-daemon-1.3.1/usr/share/google/google_daemon/desired_accounts.py 2016-01-20 19:41:29.000000000 +0100 @@ -22,17 +22,13 @@ import urllib2 -METADATA_V1_URL_PREFIX = 'http://169.254.169.254/computeMetadata/v1/' -ATTRIBUTES_URL = METADATA_V1_URL_PREFIX + '?recursive=true&%s' -INSTANCE_SSHKEYS_URL = ( - METADATA_V1_URL_PREFIX + 'instance/attributes/sshKeys?%s') -PROJECT_SSHKEYS_URL = ( - METADATA_V1_URL_PREFIX + 'project/attributes/sshKeys?%s') -WAIT_FOR_CHANGE = 'wait_for_change=true&last_etag=%s&timeout_sec=%s' +METADATA_URL = 'http://metadata.google.internal/computeMetadata/v1' +METADATA_HANG = ('/?recursive=true&alt=json&wait_for_change=true' + '&timeout_sec=%s&last_etag=%s') def KeyHasExpired(key): - """ Check to see whether an SSH key has expired. + """Check to see whether an SSH key has expired. Uses Google-specific (for now) semantics of the OpenSSH public key format's comment field to determine if an SSH key is past its expiration timestamp, and @@ -46,7 +42,8 @@ Returns: True if the key has Google-specific comment semantics and has an expiration - timestamp in the past, or False otherwise.""" + timestamp in the past, or False otherwise. + """ logging.debug('Processing key: %s', key) @@ -77,26 +74,25 @@ return False expire_str = json_obj['expireOn'] + format_str = '%Y-%m-%dT%H:%M:%S+0000' try: - expire_time = datetime.datetime.strptime(expire_str, - '%Y-%m-%dT%H:%M:%S+0000') + expire_time = datetime.datetime.strptime(expire_str, format_str) except ValueError: logging.error( - 'Expiration timestamp "%s" not in format %Y-%m-%dT%H:%M:%S+0000.', - expire_str) + 'Expiration timestamp "%s" not in format %s.', expire_str, format_str) logging.error('Not expiring key.') return False # Expire the key if and only if we have exceeded the expiration timestamp. - return (datetime.datetime.utcnow() > expire_time) + return datetime.datetime.utcnow() > expire_time def AccountDataToDictionary(data): - """Given sshKeys attribute data, construct a usermap. + """Given SSH key data, construct a usermap. Args: - data: The data returned from the metadata server's sshKeys attribute. + data: The data returned from the metadata server's SSH key attributes. Returns: A map of {'username': ssh_keys_list}. @@ -109,17 +105,17 @@ split_line = line.split(':', 1) if len(split_line) != 2: logging.warning( - 'sshKey is not a complete entry: %s', split_line) + 'SSH key is not a complete entry: %s', split_line) continue user, key = split_line if KeyHasExpired(key): logging.debug( 'Skipping expired SSH key for user %s: %s', user, key) continue - if not user in usermap: + if user not in usermap: usermap[user] = [] usermap[user].append(key) - logging.debug('User accounts: {0}'.format(usermap)) + logging.debug('User accounts: %s', usermap) return usermap @@ -129,48 +125,36 @@ def __init__(self, time_module=time, urllib2_module=urllib2): self.urllib2 = urllib2_module self.time = time_module - self.attributes_etag = 0 - self.instance_sshkeys_etag = 0 + self.etag = 0 - def _MakeHangingGetRequest(self, url, etag, timeout_secs): - """Makes a get request for the url and specifies wait_for_change. - """ - wait_for_change_query = WAIT_FOR_CHANGE % (etag, timeout_secs) - request_url = url % wait_for_change_query + def _WaitForUpdate(self, timeout_secs): + """Makes a hanging get request for the contents of the metadata server.""" + request_url = METADATA_URL + METADATA_HANG % (timeout_secs, self.etag) logging.debug('Getting url: %s', request_url) request = urllib2.Request(request_url) request.add_header('Metadata-Flavor', 'Google') return self.urllib2.urlopen(request, timeout=timeout_secs*1.1) - def _GetAttribute(self, - attribute_url, - etag=0, - timeout_secs=60): - """Fetches the attribute available at the attribute_url. + def _GetMetadataUpdate(self, timeout_secs=60): + """Fetches the content of the metadata server. Args: - attribute_url: The url to fetch. It must have a place holder where the - query with etag, and timeout can be specified to allow hanging gets. - etag: The etag to use when making the query. Don't specify if you want - the get to return immediately. timeout_secs: The timeout in seconds. Returns: - Tuple containing the string value of attribute and new etag. - If attribute doesn't exist, None. + The JSON formatted string content of the metadata server. """ try: - response = self._MakeHangingGetRequest( - attribute_url, etag=etag, timeout_secs=timeout_secs) + response = self._WaitForUpdate(timeout_secs=timeout_secs) response_info = response.info() if response_info and response_info.has_key('etag'): - etag = response_info.getheader('etag') - attribute_value = response.read() - logging.debug('response: %s', attribute_value) - return (attribute_value, etag) + self.etag = response_info.getheader('etag') + content = response.read() + logging.debug('response: %s', content) + return content except urllib2.HTTPError as e: if e.code == 404: - # The attribute doesn't exist. Return None. + # The metadata server content doesn't exist. Return None. # No need to log a warning. return None # rethrow the exception since we don't know what it is. Let the @@ -186,51 +170,25 @@ """ logging.debug('Getting desired accounts from metadata.') # Fetch the top level attribute with a hanging get - attribute_data = self._GetAttribute( - ATTRIBUTES_URL, - etag=self.attributes_etag) - if attribute_data: - # Store the project level attributes etag value. If - # we are able to successfully fetch the attributes we will - # update the class member with this value. - attributes_etag_cache = attribute_data[1] - - # Something has changed. Assume it is the sshKeys. This is not - # ideal, however, given that metadata updates are not common - # making this assumption simplifies the code complexity. - # - # sshKeys attribute can exist in either the instance attributes - # collection or the project attributes collection. If it is present - # in the instance attributes collection, then that value is used - # and the project level value is ignored. - # Check if instance attributes collection has sshKeys attribute. - # We can run this call as a hanging get since if the instance - # level attribute exists we can ignore any changes to the project - # level key. - attribute_data = self._GetAttribute( - INSTANCE_SSHKEYS_URL, - etag = self.instance_sshkeys_etag) - if attribute_data: - logging.debug('Found instance sshKeys attribute.') - # There is an sshKeys attribute on the instance. Use it - account_data = attribute_data[0] - self.instance_sshkeys_etag = attribute_data[1] - else: - # Fetch the sshKeys attribute from project collection. We cannot - # use a hanging get here since it is possible this call may take - # a long time and during that the instance metadata can change which - # we will miss. - logging.debug( - 'Instance sshKeys attribute not found. Falling back to project') - attribute_data = self._GetAttribute(PROJECT_SSHKEYS_URL) - if attribute_data: - logging.debug('Project sshKeys attribute found.') - # There is an sshKeys attribute. Use it - account_data = attribute_data[0] + metadata_content = self._GetMetadataUpdate() + metadata_dict = json.loads(metadata_content or '{}') + account_data = None + + try: + instance_data = metadata_dict['instance']['attributes'] + project_data = metadata_dict['project']['attributes'] + # Instance SSH keys that will override keys in project metadata. + instance_override = instance_data.get('override-ssh-keys') + instance_ssh = instance_data.get('sshKeys') + if instance_override or instance_ssh: + valid_keys = [instance_override, instance_ssh] else: - logging.debug('Project sshKeys attribute not found.') - # sshKeys doesn't exist for either project or instance. - account_data = None + valid_keys = [project_data.get('ssh-keys'), project_data.get('sshKeys')] + # Additional SSH keys the instance should accept. + valid_keys.append(instance_data.get('additional-ssh-keys')) + valid_keys = [key for key in valid_keys if key] + account_data = '\n'.join(valid_keys) + except KeyError: + logging.debug('Project or instance attributes were not found.') - self.attributes_etag = attributes_etag_cache return AccountDataToDictionary(account_data)
participants (1)
-
root@hilbert.suse.de