Skip to content

Commit

Permalink
feat: New Combiner CloudInstance (#3585)
Browse files Browse the repository at this point in the history
* feat: New Combiner CloudInstance

Signed-off-by: Xiangce Liu <[email protected]>

* fix doc test

Signed-off-by: Xiangce Liu <[email protected]>
(cherry picked from commit 23f7bd9)
  • Loading branch information
xiangce committed Nov 9, 2022
1 parent de32e10 commit c48c727
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/shared_combiners_catalog/cloud_instance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.. automodule:: insights.combiners.cloud_instance
:members:
:show-inheritance:
96 changes: 96 additions & 0 deletions insights/combiners/cloud_instance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Cloud Instance
==============
Combiner for the basic information of a cloud instance. It combines the
results of the following combiners and parsers:
* :py:class:`insights.combiners.cloud_provider.CloudProvider`
* :py:class:`insights.parsers.aws_instance_id.AWSInstanceIdDoc`
* :py:class:`insights.parsers.azure_instance.AzureInstanceID`
* :py:class:`insights.parsers.azure_instance.AzureInstanceType`
* :py:class:`insights.parsers.gcp_instance_type.GCPInstanceType`
* :py:class:`insights.parsers.subscription_manager.SubscriptionManagerFacts`
"""
from insights import SkipComponent
from insights.core.plugins import combiner, ContentException
from insights.parsers.aws_instance_id import AWSInstanceIdDoc
from insights.parsers.azure_instance import AzureInstanceID, AzureInstanceType
from insights.parsers.gcp_instance_type import GCPInstanceType
from insights.parsers.subscription_manager import SubscriptionManagerFacts
from insights.combiners.cloud_provider import CloudProvider


# "google" is used in class:`insights.combiners.cloud_provider.CloudProvider`.
# but 'gcp' is outputted in "subscription-manager facts"
rhsm_type_maps = {
"google": 'gcp'
}


@combiner(
CloudProvider,
[
AWSInstanceIdDoc,
AzureInstanceID,
AzureInstanceType,
GCPInstanceType,
SubscriptionManagerFacts,
]
)
class CloudInstance(object):
"""
Class to provide the basic information of a cloud instance.
Attributes:
provider (str): The cloud provider, e.g. "aws", "azure", "ibm",
"google", or "alibaba". It's from the value of
:class:`insights.combiners.cloud_provider.CloudProvider.cloud_provider`
id (str): The ID of the cloud instance
type (str): The type of the cloud instance.
Different cloud providers have different illustration of the
`type` and `size`, here for this Combiner, we treat the `type` and
`size` as the same. E.g.::
- "Standard_L64s_v2" for Azure
- "x1.16xlarge" for AWS
- "m1-megamem-96" for GCP
size (str): Alias of the `type`
Examples:
>>> ci.provider
'aws'
>>> ci.id == 'i-1234567890abcdef0'
True
>>> ci.type == 't2.micro'
True
>>> ci.size == 't2.micro'
True
"""
def __init__(self, cp, aws=None, azure_id=None, azure_type=None,
gcp=None, facts=None):
self.provider = cp.cloud_provider
self.id = None
# 1. Get from the Cloud REST API at first
if aws:
self.id = aws.get('instanceId')
self.type = aws.get('instanceType')
elif azure_id and azure_type:
self.id = azure_id.id
self.type = azure_type.raw
elif gcp:
self.type = gcp.raw
# 2. Check the "subscription-manager facts"
if self.id is None and facts:
cp_name = rhsm_type_maps.get(self.provider, self.provider)
key = "{0}_instance_id".format(cp_name)
if key not in facts:
raise ContentException("Unmatched/unsupported types!")
self.id = facts[key]
# The instance id is the key attribute of this Combiner
if self.id is None:
raise SkipComponent
# 'size' is the alias of 'type'
self.size = self.type
82 changes: 82 additions & 0 deletions insights/tests/combiners/test_cloud_instance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import pytest
import doctest
from insights import SkipComponent
from insights.core.plugins import ContentException
from insights.parsers.installed_rpms import InstalledRpms
from insights.parsers.gcp_instance_type import GCPInstanceType
from insights.parsers.aws_instance_id import AWSInstanceIdDoc
from insights.parsers.azure_instance import AzureInstanceID, AzureInstanceType
from insights.parsers.subscription_manager import SubscriptionManagerFacts
from insights.combiners import cloud_instance
from insights.combiners.cloud_provider import CloudProvider
from insights.combiners.cloud_instance import CloudInstance
from insights.tests import context_wrap
from insights.tests.parsers.test_gcp_instance_type import GOOGLE_TYPE_1
from insights.tests.parsers.test_aws_instance_id import AWS_ID_DOC
from insights.tests.parsers.test_azure_instance import AZURE_ID, AZURE_TYPE_2
from insights.tests.parsers.test_subscription_manager import INPUT_NORMAL_1
from insights.tests.combiners.test_cloud_provider import RPMS_AWS, RPMS_GOOGLE, RPMS_AZURE

GOOGLE_RHSM_FACTS = """
gcp_instance_id: 567890567890
network.ipv6_address: ::1
uname.sysname: Linux
""".strip()


def test_cloud_instance_google():
rpms = InstalledRpms(context_wrap(RPMS_GOOGLE))
_type = GCPInstanceType(context_wrap(GOOGLE_TYPE_1))
cp = CloudProvider(rpms, None, None, None)
facts = SubscriptionManagerFacts(context_wrap(GOOGLE_RHSM_FACTS))
ret = CloudInstance(cp, None, None, None, _type, facts)
assert ret.provider == CloudProvider.GOOGLE
assert ret.id == "567890567890"
assert ret.type == "n2-highcpu-16"
assert ret.size == "n2-highcpu-16"


def test_cloud_instance_aws():
rpms = InstalledRpms(context_wrap(RPMS_AWS))
_id = AWSInstanceIdDoc(context_wrap(AWS_ID_DOC))
cp = CloudProvider(rpms, None, None, None)
ret = CloudInstance(cp, _id, None, None, None, None)
assert ret.provider == CloudProvider.AWS
assert ret.id == "i-1234567890abcdef0"
assert ret.type == "t2.micro"
assert ret.size == "t2.micro"


def test_cloud_instance_azure():
rpms = InstalledRpms(context_wrap(RPMS_AZURE))
_id = AzureInstanceID(context_wrap(AZURE_ID))
_type = AzureInstanceType(context_wrap(AZURE_TYPE_2))
cp = CloudProvider(rpms, None, None, None)
ret = CloudInstance(cp, None, _id, _type, None, None)
assert ret.provider == CloudProvider.AZURE
assert ret.id == "f904ece8-c6c1-4b5c-881f-309b50f25e50"
assert ret.type == "Standard_NV48s_v3"
assert ret.size == "Standard_NV48s_v3"


def test_cloud_instance_ex():
rpms = InstalledRpms(context_wrap(RPMS_GOOGLE))
_type = GCPInstanceType(context_wrap(GOOGLE_TYPE_1))
cp = CloudProvider(rpms, None, None, None)
aws_facts = SubscriptionManagerFacts(context_wrap(INPUT_NORMAL_1))

with pytest.raises(ContentException) as ce:
CloudInstance(cp, None, None, None, None, aws_facts)
assert "Unmatched" in str(ce)

with pytest.raises(SkipComponent):
CloudInstance(cp, None, None, None, _type, None)


def test_cloud_instance_doc():
rpms = InstalledRpms(context_wrap(RPMS_AWS))
_id = AWSInstanceIdDoc(context_wrap(AWS_ID_DOC))
cp = CloudProvider(rpms, None, None, None)
env = {'ci': CloudInstance(cp, _id, None, None, None, None)}
failed, total = doctest.testmod(cloud_instance, globs=env)
assert failed == 0

0 comments on commit c48c727

Please sign in to comment.