-
Notifications
You must be signed in to change notification settings - Fork 296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add compute engine metadata client #11
Merged
Merged
Changes from 3 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
2b518a2
Add compute engine metadata client
60eb5b4
Address review comments
61dbe8e
Update pylintrc.tests to allow foo and bar sentinels.
d4b4398
Address review comments
fb6038e
Address review comments
39b9875
Add docstring examples
4debe66
Add remove argument to update_query
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Copyright 2016 Google Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
# Copyright 2016 Google Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Provides helper methods for talking to the Compute Engine metadata server. | ||
|
||
See https://cloud.google.com/compute/docs/metadata for more details. | ||
""" | ||
|
||
import datetime | ||
import json | ||
import os | ||
|
||
from six.moves import http_client | ||
from six.moves.urllib import parse as urlparse | ||
|
||
from google.auth import _helpers | ||
from google.auth import exceptions | ||
|
||
_METADATA_ROOT = 'http://metadata.google.internal/computeMetadata/v1/' | ||
|
||
# This is used to ping the metadata server, it avoids the cost of a DNS | ||
# lookup. | ||
_METADATA_IP_ROOT = 'http://169.254.169.254' | ||
_METADATA_FLAVOR_HEADER = 'metdata-flavor' | ||
_METADATA_FLAVOR_VALUE = 'Google' | ||
_METADATA_HEADERS = {_METADATA_FLAVOR_HEADER: _METADATA_FLAVOR_VALUE} | ||
|
||
# Timeout in seconds to wait for the GCE metadata server when detecting the | ||
# GCE environment. | ||
try: | ||
_METADATA_DEFAULT_TIMEOUT = int(os.getenv('GCE_METADATA_TIMEOUT', 3)) | ||
except ValueError: # pragma: NO COVER | ||
_METADATA_DEFAULT_TIMEOUT = 3 | ||
|
||
|
||
def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT): | ||
"""Checks to see if the metadata server is available. | ||
|
||
Args: | ||
request (google.auth.transport.Request): A callable used to make | ||
HTTP requests. | ||
timeout (int): How long to wait for the metadata server to respond. | ||
|
||
Returns: | ||
bool: True if the metadata server is reachable, False otherwise. | ||
""" | ||
# NOTE: The explicit ``timeout`` is a workaround. The underlying | ||
# issue is that resolving an unknown host on some networks will take | ||
# 20-30 seconds; making this timeout short fixes the issue, but | ||
# could lead to false negatives in the event that we are on GCE, but | ||
# the metadata resolution was particularly slow. The latter case is | ||
# "unlikely". | ||
try: | ||
response = request( | ||
url=_METADATA_IP_ROOT, method='GET', headers=_METADATA_HEADERS, | ||
timeout=timeout) | ||
|
||
metadata_flavor = response.headers.get(_METADATA_FLAVOR_HEADER) | ||
return (response.status == http_client.OK and | ||
metadata_flavor == _METADATA_FLAVOR_VALUE) | ||
|
||
except exceptions.TransportError: | ||
# logger.info('Timeout attempting to reach GCE metadata service.') | ||
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong. |
||
return False | ||
|
||
|
||
def get(request, path, root=_METADATA_ROOT, recursive=None): | ||
"""Fetch a resource from the metadata server. | ||
|
||
Args: | ||
request (google.auth.transport.Request): A callable used to make | ||
HTTP requests. | ||
path (str): The resource to retrieve. For example, | ||
``'instance/service-accounts/defualt'``. | ||
root (str): The full path to the metadata server root. | ||
recursive (bool): Whether to do a recursive query of metadata. See | ||
https://cloud.google.com/compute/docs/metadata#aggcontents for more | ||
details. | ||
|
||
Returns: | ||
Union[Mapping, str]: If the metadata server returns JSON, a mapping of | ||
the decoded JSON is return. Otherwise, the response content is | ||
returned as a string. | ||
|
||
Raises: | ||
google.auth.exceptions.TransportError: if an error occurred while | ||
retrieving metadata. | ||
""" | ||
url = urlparse.urljoin(root, path) | ||
url = _helpers.update_query(url, {'recursive': recursive}) | ||
|
||
response = request(url=url, method='GET', headers=_METADATA_HEADERS) | ||
|
||
if response.status == http_client.OK: | ||
content = _helpers.from_bytes(response.data) | ||
if response.headers['content-type'] == 'application/json': | ||
try: | ||
return json.loads(content) | ||
except ValueError: | ||
raise exceptions.TransportError( | ||
'Received invalid JSON from the Google Compute Engine' | ||
'metadata service: {:.20}'.format(content)) | ||
else: | ||
return content | ||
else: | ||
raise exceptions.TransportError( | ||
'Failed to retrieve {} from the Google Compute Engine' | ||
'metadata service. Status: {} Response:\n{}'.format( | ||
url, response.status, response.data), response) | ||
|
||
|
||
def get_service_account_info(request, service_account='default'): | ||
"""Get information about a service account from the metadata server. | ||
|
||
Args: | ||
request (google.auth.transport.Request): A callable used to make | ||
HTTP requests. | ||
service_account (str): The string 'default' or a service account email | ||
address. The determines which service account for which to acquire | ||
information. | ||
|
||
Returns: | ||
Mapping: The service account's information, for example:: | ||
|
||
{ | ||
'email': '...', | ||
'scopes': ['scope', ...], | ||
'aliases': ['default', '...'] | ||
} | ||
|
||
Raises: | ||
google.auth.exceptions.TransportError: if an error occurred while | ||
retrieving metadata. | ||
""" | ||
return get( | ||
request, | ||
'instance/service-accounts/{0}/'.format(service_account), | ||
recursive=True) | ||
|
||
|
||
def get_service_account_token(request, service_account='default'): | ||
"""Get the OAuth 2.0 access token for a service account. | ||
|
||
Args: | ||
request (google.auth.transport.Request): A callable used to make | ||
HTTP requests. | ||
service_account (str): The string 'default' or a service account email | ||
address. The determines which service account for which to acquire | ||
an access token. | ||
|
||
Returns: | ||
Union[str, datetime]: The access token and its expiration. | ||
|
||
Raises: | ||
google.auth.exceptions.TransportError: if an error occurred while | ||
retrieving metadata. | ||
""" | ||
token_json = get( | ||
request, | ||
'instance/service-accounts/{0}/token'.format(service_account)) | ||
token_expiry = _helpers.utcnow() + datetime.timedelta( | ||
seconds=token_json['expires_in']) | ||
return token_json['access_token'], token_expiry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong.