1# Copyright 2016 Google Inc. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Provides helper methods for talking to the Compute Engine metadata server. 16 17See https://cloud.google.com/compute/docs/metadata 18""" 19 20import datetime 21import json 22import os 23 24from six.moves import http_client 25from six.moves.urllib import parse as urlparse 26 27from oauth2client import _helpers 28from oauth2client import client 29from oauth2client import transport 30 31 32METADATA_ROOT = 'http://{}/computeMetadata/v1/'.format( 33 os.getenv('GCE_METADATA_ROOT', 'metadata.google.internal')) 34METADATA_HEADERS = {'Metadata-Flavor': 'Google'} 35 36 37def get(http, path, root=METADATA_ROOT, recursive=None): 38 """Fetch a resource from the metadata server. 39 40 Args: 41 http: an object to be used to make HTTP requests. 42 path: A string indicating the resource to retrieve. For example, 43 'instance/service-accounts/default' 44 root: A string indicating the full path to the metadata server root. 45 recursive: A boolean indicating whether to do a recursive query of 46 metadata. See 47 https://cloud.google.com/compute/docs/metadata#aggcontents 48 49 Returns: 50 A dictionary if the metadata server returns JSON, otherwise a string. 51 52 Raises: 53 http_client.HTTPException if an error corrured while 54 retrieving metadata. 55 """ 56 url = urlparse.urljoin(root, path) 57 url = _helpers._add_query_parameter(url, 'recursive', recursive) 58 59 response, content = transport.request( 60 http, url, headers=METADATA_HEADERS) 61 62 if response.status == http_client.OK: 63 decoded = _helpers._from_bytes(content) 64 if response['content-type'] == 'application/json': 65 return json.loads(decoded) 66 else: 67 return decoded 68 else: 69 raise http_client.HTTPException( 70 'Failed to retrieve {0} from the Google Compute Engine' 71 'metadata service. Response:\n{1}'.format(url, response)) 72 73 74def get_service_account_info(http, service_account='default'): 75 """Get information about a service account from the metadata server. 76 77 Args: 78 http: an object to be used to make HTTP requests. 79 service_account: An email specifying the service account for which to 80 look up information. Default will be information for the "default" 81 service account of the current compute engine instance. 82 83 Returns: 84 A dictionary with information about the specified service account, 85 for example: 86 87 { 88 'email': '...', 89 'scopes': ['scope', ...], 90 'aliases': ['default', '...'] 91 } 92 """ 93 return get( 94 http, 95 'instance/service-accounts/{0}/'.format(service_account), 96 recursive=True) 97 98 99def get_token(http, service_account='default'): 100 """Fetch an oauth token for the 101 102 Args: 103 http: an object to be used to make HTTP requests. 104 service_account: An email specifying the service account this token 105 should represent. Default will be a token for the "default" service 106 account of the current compute engine instance. 107 108 Returns: 109 A tuple of (access token, token expiration), where access token is the 110 access token as a string and token expiration is a datetime object 111 that indicates when the access token will expire. 112 """ 113 token_json = get( 114 http, 115 'instance/service-accounts/{0}/token'.format(service_account)) 116 token_expiry = client._UTCNOW() + datetime.timedelta( 117 seconds=token_json['expires_in']) 118 return token_json['access_token'], token_expiry 119