From 24850d22230b99bdffafc3f2229826f5b89da9ea Mon Sep 17 00:00:00 2001 From: Craig Citro Date: Fri, 24 Mar 2017 14:32:09 -0700 Subject: [PATCH 1/3] Allow customizing the GCE metadata service address via an env var. The goal here is to make it possible for a user of a binary that depends on this library (eg the google cloud SDK) to be able to customize where it looks for the GCE metadata service. (An adventurous user can already customize the GCE metadata service location via the existing global vars in this library.) The only bit of awkwardness here is really the test: since this is a top-level statement, reloading is the only way to ensure it works. --- google/auth/compute_engine/_metadata.py | 5 ++-- tests/compute_engine/test__metadata.py | 40 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/google/auth/compute_engine/_metadata.py b/google/auth/compute_engine/_metadata.py index e5abf2097..606fad76d 100644 --- a/google/auth/compute_engine/_metadata.py +++ b/google/auth/compute_engine/_metadata.py @@ -30,11 +30,12 @@ _LOGGER = logging.getLogger(__name__) -_METADATA_ROOT = 'http://metadata.google.internal/computeMetadata/v1/' +_METADATA_ROOT = 'http://{}/computeMetadata/v1/'.format( + os.getenv('GCE_METADATA_ROOT', 'metadata.google.internal')) # 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_IP_ROOT = 'http://' + os.getenv('GCE_METADATA_IP', '169.254.169.254') _METADATA_FLAVOR_HEADER = 'metadata-flavor' _METADATA_FLAVOR_VALUE = 'Google' _METADATA_HEADERS = {_METADATA_FLAVOR_HEADER: _METADATA_FLAVOR_VALUE} diff --git a/tests/compute_engine/test__metadata.py b/tests/compute_engine/test__metadata.py index 6a45c426d..eda5d7369 100644 --- a/tests/compute_engine/test__metadata.py +++ b/tests/compute_engine/test__metadata.py @@ -14,10 +14,12 @@ import datetime import json +import os import mock import pytest from six.moves import http_client +from six.moves import reload_module from google.auth import _helpers from google.auth import exceptions @@ -67,6 +69,25 @@ def test_ping_failure_connection_failed(mock_request): assert not _metadata.ping(request_mock) +def test_ping_success_custom_root(mock_request): + request_mock = mock_request('', headers=_metadata._METADATA_HEADERS) + + fake_ip = '1.2.3.4' + os.environ['GCE_METADATA_IP'] = fake_ip + reload_module(_metadata) + try: + assert _metadata.ping(request_mock) + finally: + del os.environ['GCE_METADATA_IP'] + reload_module(_metadata) + + request_mock.assert_called_once_with( + method='GET', + url='http://' + fake_ip, + headers=_metadata._METADATA_HEADERS, + timeout=_metadata._METADATA_DEFAULT_TIMEOUT) + + def test_get_success_json(mock_request): key, value = 'foo', 'bar' @@ -96,6 +117,25 @@ def test_get_success_text(mock_request): assert result == data +def test_get_success_custom_root(mock_request): + request_mock = mock_request( + '{}', headers={'content-type': 'application/json'}) + + fake_root = 'another.metadata.service' + os.environ['GCE_METADATA_ROOT'] = fake_root + reload_module(_metadata) + try: + _metadata.get(request_mock, PATH) + finally: + del os.environ['GCE_METADATA_ROOT'] + reload_module(_metadata) + + request_mock.assert_called_once_with( + method='GET', + url='http://{}/computeMetadata/v1/{}'.format(fake_root, PATH), + headers=_metadata._METADATA_HEADERS) + + def test_get_failure(mock_request): request_mock = mock_request( 'Metadata error', status=http_client.NOT_FOUND) From f34f161a1e818a8196a6206123a4448fc8e48396 Mon Sep 17 00:00:00 2001 From: Craig Citro Date: Fri, 24 Mar 2017 15:18:22 -0700 Subject: [PATCH 2/3] Code review feedback --- google/auth/compute_engine/_metadata.py | 6 ++++-- google/auth/environment_vars.py | 10 ++++++++++ tests/compute_engine/test__metadata.py | 10 ++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/google/auth/compute_engine/_metadata.py b/google/auth/compute_engine/_metadata.py index 606fad76d..b35775a23 100644 --- a/google/auth/compute_engine/_metadata.py +++ b/google/auth/compute_engine/_metadata.py @@ -26,16 +26,18 @@ from six.moves.urllib import parse as urlparse from google.auth import _helpers +from google.auth import environment_vars from google.auth import exceptions _LOGGER = logging.getLogger(__name__) _METADATA_ROOT = 'http://{}/computeMetadata/v1/'.format( - os.getenv('GCE_METADATA_ROOT', 'metadata.google.internal')) + os.getenv(environment_vars.GCE_METADATA_ROOT, 'metadata.google.internal')) # This is used to ping the metadata server, it avoids the cost of a DNS # lookup. -_METADATA_IP_ROOT = 'http://' + os.getenv('GCE_METADATA_IP', '169.254.169.254') +_METADATA_IP_ROOT = 'http://{}'.format( + os.getenv(environment_vars.GCE_METADATA_IP, '169.254.169.254')) _METADATA_FLAVOR_HEADER = 'metadata-flavor' _METADATA_FLAVOR_VALUE = 'Google' _METADATA_HEADERS = {_METADATA_FLAVOR_HEADER: _METADATA_FLAVOR_VALUE} diff --git a/google/auth/environment_vars.py b/google/auth/environment_vars.py index b4ed2b28a..0110e6a3c 100644 --- a/google/auth/environment_vars.py +++ b/google/auth/environment_vars.py @@ -37,3 +37,13 @@ CLOUD_SDK_CONFIG_DIR = 'CLOUDSDK_CONFIG' """Environment variable defines the location of Google Cloud SDK's config files.""" + +# These two variables allow for customization of the addresses used when +# contacting the GCE metadata service. +GCE_METADATA_ROOT = 'GCE_METADATA_ROOT' +"""Environment variable providing an alternate hostname or host:port to be +used for GCE metadata requests.""" + +GCE_METADATA_IP = 'GCE_METADATA_IP' +"""Environment variable providing an alternate ip:port to be used for ip-only +GCE metadata requests.""" diff --git a/tests/compute_engine/test__metadata.py b/tests/compute_engine/test__metadata.py index eda5d7369..fd1823318 100644 --- a/tests/compute_engine/test__metadata.py +++ b/tests/compute_engine/test__metadata.py @@ -22,6 +22,7 @@ from six.moves import reload_module from google.auth import _helpers +from google.auth import environment_vars from google.auth import exceptions from google.auth.compute_engine import _metadata @@ -73,12 +74,13 @@ def test_ping_success_custom_root(mock_request): request_mock = mock_request('', headers=_metadata._METADATA_HEADERS) fake_ip = '1.2.3.4' - os.environ['GCE_METADATA_IP'] = fake_ip + os.environ[environment_vars.GCE_METADATA_IP] = fake_ip reload_module(_metadata) + try: assert _metadata.ping(request_mock) finally: - del os.environ['GCE_METADATA_IP'] + del os.environ[environment_vars.GCE_METADATA_IP] reload_module(_metadata) request_mock.assert_called_once_with( @@ -122,12 +124,12 @@ def test_get_success_custom_root(mock_request): '{}', headers={'content-type': 'application/json'}) fake_root = 'another.metadata.service' - os.environ['GCE_METADATA_ROOT'] = fake_root + os.environ[environment_vars.GCE_METADATA_ROOT] = fake_root reload_module(_metadata) try: _metadata.get(request_mock, PATH) finally: - del os.environ['GCE_METADATA_ROOT'] + del os.environ[environment_vars.GCE_METADATA_ROOT] reload_module(_metadata) request_mock.assert_called_once_with( From 929bcba88cbc9a7a7b52b3b5cb47ab38b5d89b30 Mon Sep 17 00:00:00 2001 From: Craig Citro Date: Fri, 24 Mar 2017 15:25:21 -0700 Subject: [PATCH 3/3] Whitespace and indentation updates. --- tests/compute_engine/test__metadata.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/compute_engine/test__metadata.py b/tests/compute_engine/test__metadata.py index fd1823318..0adf88252 100644 --- a/tests/compute_engine/test__metadata.py +++ b/tests/compute_engine/test__metadata.py @@ -78,10 +78,10 @@ def test_ping_success_custom_root(mock_request): reload_module(_metadata) try: - assert _metadata.ping(request_mock) + assert _metadata.ping(request_mock) finally: - del os.environ[environment_vars.GCE_METADATA_IP] - reload_module(_metadata) + del os.environ[environment_vars.GCE_METADATA_IP] + reload_module(_metadata) request_mock.assert_called_once_with( method='GET', @@ -126,11 +126,12 @@ def test_get_success_custom_root(mock_request): fake_root = 'another.metadata.service' os.environ[environment_vars.GCE_METADATA_ROOT] = fake_root reload_module(_metadata) + try: - _metadata.get(request_mock, PATH) + _metadata.get(request_mock, PATH) finally: - del os.environ[environment_vars.GCE_METADATA_ROOT] - reload_module(_metadata) + del os.environ[environment_vars.GCE_METADATA_ROOT] + reload_module(_metadata) request_mock.assert_called_once_with( method='GET',