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