forked from p15670423/monkey
Merge pull request #924 from shreyamalviya/env-collection-errors
Catch exceptions in AwsInstance and AzureInstance
This commit is contained in:
commit
0cc65cb346
|
@ -1,8 +1,7 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import urllib.error
|
import requests
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
from common.cloud.environment_names import Environment
|
from common.cloud.environment_names import Environment
|
||||||
from common.cloud.instance import CloudInstance
|
from common.cloud.instance import CloudInstance
|
||||||
|
@ -33,19 +32,17 @@ class AwsInstance(CloudInstance):
|
||||||
self.account_id = None
|
self.account_id = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.instance_id = urllib.request.urlopen(
|
response = requests.get(AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/instance-id', timeout=2)
|
||||||
AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/instance-id', timeout=2).read().decode()
|
self.instance_id = response.text if response else None
|
||||||
self.region = self._parse_region(
|
self.region = self._parse_region(
|
||||||
urllib.request.urlopen(
|
requests.get(AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/placement/availability-zone').text)
|
||||||
AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/placement/availability-zone').read().decode())
|
except (requests.RequestException, IOError) as e:
|
||||||
except (urllib.error.URLError, IOError) as e:
|
|
||||||
logger.debug("Failed init of AwsInstance while getting metadata: {}".format(e))
|
logger.debug("Failed init of AwsInstance while getting metadata: {}".format(e))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.account_id = self._extract_account_id(
|
self.account_id = self._extract_account_id(
|
||||||
urllib.request.urlopen(
|
requests.get(AWS_LATEST_METADATA_URI_PREFIX + 'dynamic/instance-identity/document', timeout=2).text)
|
||||||
AWS_LATEST_METADATA_URI_PREFIX + 'dynamic/instance-identity/document', timeout=2).read().decode())
|
except (requests.RequestException, json.decoder.JSONDecodeError, IOError) as e:
|
||||||
except (urllib.error.URLError, IOError) as e:
|
|
||||||
logger.debug("Failed init of AwsInstance while getting dynamic instance data: {}".format(e))
|
logger.debug("Failed init of AwsInstance while getting dynamic instance data: {}".format(e))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -0,0 +1,300 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import requests
|
||||||
|
import requests_mock
|
||||||
|
|
||||||
|
from common.cloud.aws.aws_instance import (AWS_LATEST_METADATA_URI_PREFIX,
|
||||||
|
AwsInstance)
|
||||||
|
from common.cloud.environment_names import Environment
|
||||||
|
|
||||||
|
|
||||||
|
INSTANCE_ID_RESPONSE = 'i-1234567890abcdef0'
|
||||||
|
|
||||||
|
AVAILABILITY_ZONE_RESPONSE = 'us-west-2b'
|
||||||
|
|
||||||
|
# from https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
|
||||||
|
INSTANCE_IDENTITY_DOCUMENT_RESPONSE = """
|
||||||
|
{
|
||||||
|
"devpayProductCodes": null,
|
||||||
|
"marketplaceProductCodes": ["1abc2defghijklm3nopqrs4tu"],
|
||||||
|
"availabilityZone": "us-west-2b",
|
||||||
|
"privateIp": "10.158.112.84",
|
||||||
|
"version": "2017-09-30",
|
||||||
|
"instanceId": "i-1234567890abcdef0",
|
||||||
|
"billingProducts": null,
|
||||||
|
"instanceType": "t2.micro",
|
||||||
|
"accountId": "123456789012",
|
||||||
|
"imageId": "ami-5fb8c835",
|
||||||
|
"pendingTime": "2016-11-19T16:32:11Z",
|
||||||
|
"architecture": "x86_64",
|
||||||
|
"kernelId": null,
|
||||||
|
"ramdiskId": null,
|
||||||
|
"region": "us-west-2"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
EXPECTED_INSTANCE_ID = 'i-1234567890abcdef0'
|
||||||
|
|
||||||
|
EXPECTED_REGION = 'us-west-2'
|
||||||
|
|
||||||
|
EXPECTED_ACCOUNT_ID = '123456789012'
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_aws_instance(text={'instance_id': None,
|
||||||
|
'region': None,
|
||||||
|
'account_id': None},
|
||||||
|
exception={'instance_id': None,
|
||||||
|
'region': None,
|
||||||
|
'account_id': None}):
|
||||||
|
with requests_mock.Mocker() as m:
|
||||||
|
# request made to get instance_id
|
||||||
|
url = f'{AWS_LATEST_METADATA_URI_PREFIX}meta-data/instance-id'
|
||||||
|
m.get(url, text=text['instance_id']) if text['instance_id'] else m.get(
|
||||||
|
url, exc=exception['instance_id'])
|
||||||
|
|
||||||
|
# request made to get region
|
||||||
|
url = f'{AWS_LATEST_METADATA_URI_PREFIX}meta-data/placement/availability-zone'
|
||||||
|
m.get(url, text=text['region']) if text['region'] else m.get(
|
||||||
|
url, exc=exception['region'])
|
||||||
|
|
||||||
|
# request made to get account_id
|
||||||
|
url = f'{AWS_LATEST_METADATA_URI_PREFIX}dynamic/instance-identity/document'
|
||||||
|
m.get(url, text=text['account_id']) if text['account_id'] else m.get(
|
||||||
|
url, exc=exception['account_id'])
|
||||||
|
|
||||||
|
test_aws_instance_object = AwsInstance()
|
||||||
|
return test_aws_instance_object
|
||||||
|
|
||||||
|
|
||||||
|
# all good data
|
||||||
|
@pytest.fixture
|
||||||
|
def good_data_mock_instance():
|
||||||
|
return get_test_aws_instance(text={'instance_id': INSTANCE_ID_RESPONSE,
|
||||||
|
'region': AVAILABILITY_ZONE_RESPONSE,
|
||||||
|
'account_id': INSTANCE_IDENTITY_DOCUMENT_RESPONSE})
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.is_instance()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.get_cloud_provider_name() == Environment.AWS
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_instance_id_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.get_instance_id() == EXPECTED_INSTANCE_ID
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_region_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.get_region() == EXPECTED_REGION
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_account_id_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.get_account_id() == EXPECTED_ACCOUNT_ID
|
||||||
|
|
||||||
|
|
||||||
|
# 'region' bad data
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_region_data_mock_instance():
|
||||||
|
return get_test_aws_instance(text={'instance_id': INSTANCE_ID_RESPONSE,
|
||||||
|
'region': 'in-a-different-world',
|
||||||
|
'account_id': INSTANCE_IDENTITY_DOCUMENT_RESPONSE})
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_bad_region_data(bad_region_data_mock_instance):
|
||||||
|
assert bad_region_data_mock_instance.is_instance()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_bad_region_data(bad_region_data_mock_instance):
|
||||||
|
assert bad_region_data_mock_instance.get_cloud_provider_name() == Environment.AWS
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_instance_id_bad_region_data(bad_region_data_mock_instance):
|
||||||
|
assert bad_region_data_mock_instance.get_instance_id() == EXPECTED_INSTANCE_ID
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_region_bad_region_data(bad_region_data_mock_instance):
|
||||||
|
assert bad_region_data_mock_instance.get_region() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_account_id_bad_region_data(bad_region_data_mock_instance):
|
||||||
|
assert bad_region_data_mock_instance.get_account_id() == EXPECTED_ACCOUNT_ID
|
||||||
|
|
||||||
|
|
||||||
|
# 'account_id' bad data
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_account_id_data_mock_instance():
|
||||||
|
return get_test_aws_instance(text={'instance_id': INSTANCE_ID_RESPONSE,
|
||||||
|
'region': AVAILABILITY_ZONE_RESPONSE,
|
||||||
|
'account_id': 'who-am-i'})
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_bad_account_id_data(bad_account_id_data_mock_instance):
|
||||||
|
assert bad_account_id_data_mock_instance.is_instance()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_bad_account_id_data(bad_account_id_data_mock_instance):
|
||||||
|
assert bad_account_id_data_mock_instance.get_cloud_provider_name() == Environment.AWS
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_instance_id_bad_account_id_data(bad_account_id_data_mock_instance):
|
||||||
|
assert bad_account_id_data_mock_instance.get_instance_id() == EXPECTED_INSTANCE_ID
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_region_bad_account_id_data(bad_account_id_data_mock_instance):
|
||||||
|
assert bad_account_id_data_mock_instance.get_region() == EXPECTED_REGION
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_account_id_data_bad_account_id_data(bad_account_id_data_mock_instance):
|
||||||
|
assert bad_account_id_data_mock_instance.get_account_id() is None
|
||||||
|
|
||||||
|
|
||||||
|
# 'instance_id' bad requests
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_instance_id_request_mock_instance(instance_id_exception):
|
||||||
|
return get_test_aws_instance(text={'instance_id': None,
|
||||||
|
'region': AVAILABILITY_ZONE_RESPONSE,
|
||||||
|
'account_id': INSTANCE_IDENTITY_DOCUMENT_RESPONSE},
|
||||||
|
exception={'instance_id': instance_id_exception,
|
||||||
|
'region': None,
|
||||||
|
'account_id': None})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('instance_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_is_instance_bad_instance_id_request(bad_instance_id_request_mock_instance):
|
||||||
|
assert bad_instance_id_request_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('instance_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_cloud_provider_name_bad_instance_id_request(bad_instance_id_request_mock_instance):
|
||||||
|
assert bad_instance_id_request_mock_instance.get_cloud_provider_name() == Environment.AWS
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('instance_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_instance_id_bad_instance_id_request(bad_instance_id_request_mock_instance):
|
||||||
|
assert bad_instance_id_request_mock_instance.get_instance_id() is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('instance_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_region_bad_instance_id_request(bad_instance_id_request_mock_instance):
|
||||||
|
assert bad_instance_id_request_mock_instance.get_region() is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('instance_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_account_id_bad_instance_id_request(bad_instance_id_request_mock_instance):
|
||||||
|
assert bad_instance_id_request_mock_instance.get_account_id() == EXPECTED_ACCOUNT_ID
|
||||||
|
|
||||||
|
|
||||||
|
# 'region' bad requests
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_region_request_mock_instance(region_exception):
|
||||||
|
return get_test_aws_instance(text={'instance_id': INSTANCE_ID_RESPONSE,
|
||||||
|
'region': None,
|
||||||
|
'account_id': INSTANCE_IDENTITY_DOCUMENT_RESPONSE},
|
||||||
|
exception={'instance_id': None,
|
||||||
|
'region': region_exception,
|
||||||
|
'account_id': None})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('region_exception', [requests.RequestException, IOError])
|
||||||
|
def test_is_instance_bad_region_request(bad_region_request_mock_instance):
|
||||||
|
assert bad_region_request_mock_instance.is_instance()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('region_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_cloud_provider_name_bad_region_request(bad_region_request_mock_instance):
|
||||||
|
assert bad_region_request_mock_instance.get_cloud_provider_name() == Environment.AWS
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('region_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_instance_id_bad_region_request(bad_region_request_mock_instance):
|
||||||
|
assert bad_region_request_mock_instance.get_instance_id() == EXPECTED_INSTANCE_ID
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('region_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_region_bad_region_request(bad_region_request_mock_instance):
|
||||||
|
assert bad_region_request_mock_instance.get_region() is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('region_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_account_id_bad_region_request(bad_region_request_mock_instance):
|
||||||
|
assert bad_region_request_mock_instance.get_account_id() == EXPECTED_ACCOUNT_ID
|
||||||
|
|
||||||
|
|
||||||
|
# 'account_id' bad requests
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_account_id_request_mock_instance(account_id_exception):
|
||||||
|
return get_test_aws_instance(text={'instance_id': INSTANCE_ID_RESPONSE,
|
||||||
|
'region': AVAILABILITY_ZONE_RESPONSE,
|
||||||
|
'account_id': None},
|
||||||
|
exception={'instance_id': None,
|
||||||
|
'region': None,
|
||||||
|
'account_id': account_id_exception})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('account_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_is_instance_bad_account_id_request(bad_account_id_request_mock_instance):
|
||||||
|
assert bad_account_id_request_mock_instance.is_instance()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('account_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_cloud_provider_name_bad_account_id_request(bad_account_id_request_mock_instance):
|
||||||
|
assert bad_account_id_request_mock_instance.get_cloud_provider_name() == Environment.AWS
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('account_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_instance_id_bad_account_id_request(bad_account_id_request_mock_instance):
|
||||||
|
assert bad_account_id_request_mock_instance.get_instance_id() == EXPECTED_INSTANCE_ID
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('account_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_region_bad_account_id_request(bad_account_id_request_mock_instance):
|
||||||
|
assert bad_account_id_request_mock_instance.get_region() == EXPECTED_REGION
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('account_id_exception', [requests.RequestException, IOError])
|
||||||
|
def test_get_account_id_bad_account_id_request(bad_account_id_request_mock_instance):
|
||||||
|
assert bad_account_id_request_mock_instance.get_account_id() is None
|
||||||
|
|
||||||
|
|
||||||
|
# not found request
|
||||||
|
@pytest.fixture
|
||||||
|
def not_found_request_mock_instance():
|
||||||
|
with requests_mock.Mocker() as m:
|
||||||
|
# request made to get instance_id
|
||||||
|
url = f'{AWS_LATEST_METADATA_URI_PREFIX}meta-data/instance-id'
|
||||||
|
m.get(url, status_code=404)
|
||||||
|
|
||||||
|
# request made to get region
|
||||||
|
url = f'{AWS_LATEST_METADATA_URI_PREFIX}meta-data/placement/availability-zone'
|
||||||
|
m.get(url)
|
||||||
|
|
||||||
|
# request made to get account_id
|
||||||
|
url = f'{AWS_LATEST_METADATA_URI_PREFIX}dynamic/instance-identity/document'
|
||||||
|
m.get(url)
|
||||||
|
|
||||||
|
not_found_aws_instance_object = AwsInstance()
|
||||||
|
return not_found_aws_instance_object
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.get_cloud_provider_name() == Environment.AWS
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_instance_id_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.get_instance_id() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_region_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.get_region() is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_account_id_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.get_account_id() is None
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import simplejson
|
||||||
|
|
||||||
from common.cloud.environment_names import Environment
|
from common.cloud.environment_names import Environment
|
||||||
from common.cloud.instance import CloudInstance
|
from common.cloud.instance import CloudInstance
|
||||||
|
@ -18,7 +19,7 @@ class AzureInstance(CloudInstance):
|
||||||
Based on Azure metadata service: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service
|
Based on Azure metadata service: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service
|
||||||
"""
|
"""
|
||||||
def is_instance(self):
|
def is_instance(self):
|
||||||
return self.on_azure
|
return self._on_azure
|
||||||
|
|
||||||
def get_cloud_provider_name(self) -> Environment:
|
def get_cloud_provider_name(self) -> Environment:
|
||||||
return Environment.AZURE
|
return Environment.AZURE
|
||||||
|
@ -30,24 +31,22 @@ class AzureInstance(CloudInstance):
|
||||||
self.instance_name = None
|
self.instance_name = None
|
||||||
self.instance_id = None
|
self.instance_id = None
|
||||||
self.location = None
|
self.location = None
|
||||||
self.on_azure = False
|
self._on_azure = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(AZURE_METADATA_SERVICE_URL,
|
response = requests.get(AZURE_METADATA_SERVICE_URL,
|
||||||
headers={"Metadata": "true"},
|
headers={"Metadata": "true"},
|
||||||
timeout=SHORT_REQUEST_TIMEOUT)
|
timeout=SHORT_REQUEST_TIMEOUT)
|
||||||
self.on_azure = True
|
|
||||||
|
|
||||||
# If not on cloud, the metadata URL is non-routable and the connection will fail.
|
# If not on cloud, the metadata URL is non-routable and the connection will fail.
|
||||||
# If on AWS, should get 404 since the metadata service URL is different, so bool(response) will be false.
|
# If on AWS, should get 404 since the metadata service URL is different, so bool(response) will be false.
|
||||||
if response:
|
if response:
|
||||||
logger.debug("On Azure. Trying to parse metadata.")
|
logger.debug("Trying to parse Azure metadata.")
|
||||||
self.try_parse_response(response)
|
self.try_parse_response(response)
|
||||||
else:
|
else:
|
||||||
logger.warning("On Azure, but metadata response not ok: {}".format(response.status_code))
|
logger.warning(f"Metadata response not ok: {response.status_code}")
|
||||||
except requests.RequestException:
|
except requests.RequestException:
|
||||||
logger.debug("Failed to get response from Azure metadata service: This instance is not on Azure.")
|
logger.debug("Failed to get response from Azure metadata service: This instance is not on Azure.")
|
||||||
self.on_azure = False
|
|
||||||
|
|
||||||
def try_parse_response(self, response):
|
def try_parse_response(self, response):
|
||||||
try:
|
try:
|
||||||
|
@ -55,5 +54,6 @@ class AzureInstance(CloudInstance):
|
||||||
self.instance_name = response_data["compute"]["name"]
|
self.instance_name = response_data["compute"]["name"]
|
||||||
self.instance_id = response_data["compute"]["vmId"]
|
self.instance_id = response_data["compute"]["vmId"]
|
||||||
self.location = response_data["compute"]["location"]
|
self.location = response_data["compute"]["location"]
|
||||||
except KeyError:
|
self._on_azure = True
|
||||||
logger.exception("Error while parsing response from Azure metadata service.")
|
except (KeyError, simplejson.errors.JSONDecodeError) as e:
|
||||||
|
logger.exception(f"Error while parsing response from Azure metadata service: {e}")
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
import pytest
|
||||||
|
import requests
|
||||||
|
import requests_mock
|
||||||
|
import simplejson
|
||||||
|
|
||||||
|
from common.cloud.azure.azure_instance import (AZURE_METADATA_SERVICE_URL,
|
||||||
|
AzureInstance)
|
||||||
|
from common.cloud.environment_names import Environment
|
||||||
|
|
||||||
|
|
||||||
|
GOOD_DATA = {
|
||||||
|
'compute': {'azEnvironment': 'AZUREPUBLICCLOUD',
|
||||||
|
'isHostCompatibilityLayerVm': 'true',
|
||||||
|
'licenseType': 'Windows_Client',
|
||||||
|
'location': 'westus',
|
||||||
|
'name': 'examplevmname',
|
||||||
|
'offer': 'Windows',
|
||||||
|
'osProfile': {'adminUsername': 'admin',
|
||||||
|
'computerName': 'examplevmname',
|
||||||
|
'disablePasswordAuthentication': 'true'},
|
||||||
|
'osType': 'linux',
|
||||||
|
'placementGroupId': 'f67c14ab-e92c-408c-ae2d-da15866ec79a',
|
||||||
|
'plan': {'name': 'planName',
|
||||||
|
'product': 'planProduct',
|
||||||
|
'publisher': 'planPublisher'},
|
||||||
|
'platformFaultDomain': '36',
|
||||||
|
'platformUpdateDomain': '42',
|
||||||
|
'publicKeys': [{'keyData': 'ssh-rsa 0',
|
||||||
|
'path': '/home/user/.ssh/authorized_keys0'},
|
||||||
|
{'keyData': 'ssh-rsa 1',
|
||||||
|
'path': '/home/user/.ssh/authorized_keys1'}],
|
||||||
|
'publisher': 'RDFE-Test-Microsoft-Windows-Server-Group',
|
||||||
|
'resourceGroupName': 'macikgo-test-may-23',
|
||||||
|
'resourceId': '/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/'
|
||||||
|
'providers/Microsoft.Compute/virtualMachines/examplevmname',
|
||||||
|
'securityProfile': {'secureBootEnabled': 'true',
|
||||||
|
'virtualTpmEnabled': 'false'},
|
||||||
|
'sku': 'Windows-Server-2012-R2-Datacenter',
|
||||||
|
'storageProfile': {'dataDisks': [{'caching': 'None',
|
||||||
|
'createOption': 'Empty',
|
||||||
|
'diskSizeGB': '1024',
|
||||||
|
'image': {'uri': ''},
|
||||||
|
'lun': '0',
|
||||||
|
'managedDisk': {'id': '/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/'
|
||||||
|
'resourceGroups/macikgo-test-may-23/providers/'
|
||||||
|
'Microsoft.Compute/disks/exampledatadiskname',
|
||||||
|
'storageAccountType': 'Standard_LRS'},
|
||||||
|
'name': 'exampledatadiskname',
|
||||||
|
'vhd': {'uri': ''},
|
||||||
|
'writeAcceleratorEnabled': 'false'}],
|
||||||
|
'imageReference': {'id': '',
|
||||||
|
'offer': 'UbuntuServer',
|
||||||
|
'publisher': 'Canonical',
|
||||||
|
'sku': '16.04.0-LTS',
|
||||||
|
'version': 'latest'},
|
||||||
|
'osDisk': {'caching': 'ReadWrite',
|
||||||
|
'createOption': 'FromImage',
|
||||||
|
'diskSizeGB': '30',
|
||||||
|
'diffDiskSettings': {'option': 'Local'},
|
||||||
|
'encryptionSettings': {'enabled': 'false'},
|
||||||
|
'image': {'uri': ''},
|
||||||
|
'managedDisk': {'id': '/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/'
|
||||||
|
'resourceGroups/macikgo-test-may-23/providers/'
|
||||||
|
'Microsoft.Compute/disks/exampleosdiskname',
|
||||||
|
'storageAccountType': 'Standard_LRS'},
|
||||||
|
'name': 'exampleosdiskname',
|
||||||
|
'osType': 'Linux',
|
||||||
|
'vhd': {'uri': ''},
|
||||||
|
'writeAcceleratorEnabled': 'false'}},
|
||||||
|
'subscriptionId': 'xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx',
|
||||||
|
'tags': 'baz:bash;foo:bar',
|
||||||
|
'version': '15.05.22',
|
||||||
|
'vmId': '02aab8a4-74ef-476e-8182-f6d2ba4166a6',
|
||||||
|
'vmScaleSetName': 'crpteste9vflji9',
|
||||||
|
'vmSize': 'Standard_A3',
|
||||||
|
'zone': ''},
|
||||||
|
'network': {'interface': [{'ipv4': {'ipAddress': [{'privateIpAddress': '10.144.133.132',
|
||||||
|
'publicIpAddress': ''}],
|
||||||
|
'subnet': [{'address': '10.144.133.128',
|
||||||
|
'prefix': '26'}]},
|
||||||
|
'ipv6': {'ipAddress': []},
|
||||||
|
'macAddress': '0011AAFFBB22'}]}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BAD_DATA_NOT_JSON = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/\
|
||||||
|
xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml">\n<head>\n<meta content="text/html; charset=utf-8" \
|
||||||
|
http-equiv="Content-Type" />\n<meta content="no-cache" http-equiv="Pragma" />\n<title>Waiting...</title>\n<script type="text/\
|
||||||
|
javascript">\nvar pageName = \'/\';\ntop.location.replace(pageName);\n</script>\n</head>\n<body> </body>\n</html>\n'
|
||||||
|
|
||||||
|
|
||||||
|
BAD_DATA_JSON = {'': ''}
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_azure_instance(url, **kwargs):
|
||||||
|
with requests_mock.Mocker() as m:
|
||||||
|
m.get(url, **kwargs)
|
||||||
|
test_azure_instance_object = AzureInstance()
|
||||||
|
return test_azure_instance_object
|
||||||
|
|
||||||
|
|
||||||
|
# good request, good data
|
||||||
|
@pytest.fixture
|
||||||
|
def good_data_mock_instance():
|
||||||
|
return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, text=simplejson.dumps(GOOD_DATA))
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.is_instance()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.get_cloud_provider_name() == Environment.AZURE
|
||||||
|
|
||||||
|
|
||||||
|
def test_try_parse_response_good_data(good_data_mock_instance):
|
||||||
|
assert good_data_mock_instance.instance_name == GOOD_DATA['compute']['name']
|
||||||
|
assert good_data_mock_instance.instance_id == GOOD_DATA['compute']['vmId']
|
||||||
|
assert good_data_mock_instance.location == GOOD_DATA['compute']['location']
|
||||||
|
|
||||||
|
|
||||||
|
# good request, bad data (json)
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_data_json_mock_instance():
|
||||||
|
return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, text=simplejson.dumps(BAD_DATA_JSON))
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_bad_data_json(bad_data_json_mock_instance):
|
||||||
|
assert bad_data_json_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_bad_data_json(bad_data_json_mock_instance):
|
||||||
|
assert bad_data_json_mock_instance.get_cloud_provider_name() == Environment.AZURE
|
||||||
|
|
||||||
|
|
||||||
|
def test_instance_attributes_bad_data_json(bad_data_json_mock_instance):
|
||||||
|
assert bad_data_json_mock_instance.instance_name is None
|
||||||
|
assert bad_data_json_mock_instance.instance_id is None
|
||||||
|
assert bad_data_json_mock_instance.location is None
|
||||||
|
|
||||||
|
|
||||||
|
# good request, bad data (not json)
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_data_not_json_mock_instance():
|
||||||
|
return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, text=BAD_DATA_NOT_JSON)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_bad_data_not_json(bad_data_not_json_mock_instance):
|
||||||
|
assert bad_data_not_json_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_bad_data_not_json(bad_data_not_json_mock_instance):
|
||||||
|
assert bad_data_not_json_mock_instance.get_cloud_provider_name() == Environment.AZURE
|
||||||
|
|
||||||
|
|
||||||
|
def test_instance_attributes_bad_data_not_json(bad_data_not_json_mock_instance):
|
||||||
|
assert bad_data_not_json_mock_instance.instance_name is None
|
||||||
|
assert bad_data_not_json_mock_instance.instance_id is None
|
||||||
|
assert bad_data_not_json_mock_instance.location is None
|
||||||
|
|
||||||
|
|
||||||
|
# bad request
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_request_mock_instance():
|
||||||
|
return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, exc=requests.RequestException)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_bad_request(bad_request_mock_instance):
|
||||||
|
assert bad_request_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_bad_request(bad_request_mock_instance):
|
||||||
|
assert bad_request_mock_instance.get_cloud_provider_name() == Environment.AZURE
|
||||||
|
|
||||||
|
|
||||||
|
def test_instance_attributes_bad_request(bad_request_mock_instance):
|
||||||
|
assert bad_request_mock_instance.instance_name is None
|
||||||
|
assert bad_request_mock_instance.instance_id is None
|
||||||
|
assert bad_request_mock_instance.location is None
|
||||||
|
|
||||||
|
|
||||||
|
# not found request
|
||||||
|
@pytest.fixture
|
||||||
|
def not_found_request_mock_instance():
|
||||||
|
return get_test_azure_instance(AZURE_METADATA_SERVICE_URL, status_code=404)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.get_cloud_provider_name() == Environment.AZURE
|
||||||
|
|
||||||
|
|
||||||
|
def test_instance_attributes_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.instance_name is None
|
||||||
|
assert not_found_request_mock_instance.instance_id is None
|
||||||
|
assert not_found_request_mock_instance.location is None
|
|
@ -17,13 +17,13 @@ class GcpInstance(CloudInstance):
|
||||||
Used to determine if on GCP. See https://cloud.google.com/compute/docs/storing-retrieving-metadata#runninggce
|
Used to determine if on GCP. See https://cloud.google.com/compute/docs/storing-retrieving-metadata#runninggce
|
||||||
"""
|
"""
|
||||||
def is_instance(self):
|
def is_instance(self):
|
||||||
return self.on_gcp
|
return self._on_gcp
|
||||||
|
|
||||||
def get_cloud_provider_name(self) -> Environment:
|
def get_cloud_provider_name(self) -> Environment:
|
||||||
return Environment.GCP
|
return Environment.GCP
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.on_gcp = False
|
self._on_gcp = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# If not on GCP, this domain shouldn't resolve.
|
# If not on GCP, this domain shouldn't resolve.
|
||||||
|
@ -31,7 +31,7 @@ class GcpInstance(CloudInstance):
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
logger.debug("Got ok metadata response: on GCP")
|
logger.debug("Got ok metadata response: on GCP")
|
||||||
self.on_gcp = True
|
self._on_gcp = True
|
||||||
|
|
||||||
if "Metadata-Flavor" not in response.headers:
|
if "Metadata-Flavor" not in response.headers:
|
||||||
logger.warning("Got unexpected GCP Metadata format")
|
logger.warning("Got unexpected GCP Metadata format")
|
||||||
|
@ -42,4 +42,4 @@ class GcpInstance(CloudInstance):
|
||||||
logger.warning("On GCP, but metadata response not ok: {}".format(response.status_code))
|
logger.warning("On GCP, but metadata response not ok: {}".format(response.status_code))
|
||||||
except requests.RequestException:
|
except requests.RequestException:
|
||||||
logger.debug("Failed to get response from GCP metadata service: This instance is not on GCP")
|
logger.debug("Failed to get response from GCP metadata service: This instance is not on GCP")
|
||||||
self.on_gcp = False
|
self._on_gcp = False
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
import pytest
|
||||||
|
import requests
|
||||||
|
import requests_mock
|
||||||
|
|
||||||
|
from common.cloud.environment_names import Environment
|
||||||
|
from common.cloud.gcp.gcp_instance import GCP_METADATA_SERVICE_URL, GcpInstance
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_gcp_instance(url, **kwargs):
|
||||||
|
with requests_mock.Mocker() as m:
|
||||||
|
m.get(url, **kwargs)
|
||||||
|
test_gcp_instance_object = GcpInstance()
|
||||||
|
return test_gcp_instance_object
|
||||||
|
|
||||||
|
|
||||||
|
# good request
|
||||||
|
@pytest.fixture
|
||||||
|
def good_request_mock_instance():
|
||||||
|
return get_test_gcp_instance(GCP_METADATA_SERVICE_URL)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_good_request(good_request_mock_instance):
|
||||||
|
assert good_request_mock_instance.is_instance()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_good_request(good_request_mock_instance):
|
||||||
|
assert good_request_mock_instance.get_cloud_provider_name() == Environment.GCP
|
||||||
|
|
||||||
|
|
||||||
|
# bad request
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_request_mock_instance():
|
||||||
|
return get_test_gcp_instance(GCP_METADATA_SERVICE_URL, exc=requests.RequestException)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_bad_request(bad_request_mock_instance):
|
||||||
|
assert bad_request_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_bad_request(bad_request_mock_instance):
|
||||||
|
assert bad_request_mock_instance.get_cloud_provider_name() == Environment.GCP
|
||||||
|
|
||||||
|
|
||||||
|
# not found request
|
||||||
|
@pytest.fixture
|
||||||
|
def not_found_request_mock_instance():
|
||||||
|
return get_test_gcp_instance(GCP_METADATA_SERVICE_URL, status_code=404)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_instance_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.is_instance() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cloud_provider_name_not_found_request(not_found_request_mock_instance):
|
||||||
|
assert not_found_request_mock_instance.get_cloud_provider_name() == Environment.GCP
|
|
@ -18,6 +18,7 @@ pycryptodome==3.9.8
|
||||||
pytest>=5.4
|
pytest>=5.4
|
||||||
python-dateutil>=2.1,<3.0.0
|
python-dateutil>=2.1,<3.0.0
|
||||||
requests>=2.24
|
requests>=2.24
|
||||||
|
requests-mock==1.8.0
|
||||||
ring>=0.7.3
|
ring>=0.7.3
|
||||||
stix2>=2.0.2
|
stix2>=2.0.2
|
||||||
six>=1.13.0
|
six>=1.13.0
|
||||||
|
|
Loading…
Reference in New Issue