Skip to content

Commit

Permalink
[aws][fix] Fetch instance types in all regions (#1374)
Browse files Browse the repository at this point in the history
  • Loading branch information
aquamatthias committed Jan 23, 2023
1 parent aacc850 commit 26973c3
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 19 deletions.
1 change: 0 additions & 1 deletion plugins/aws/resoto_plugin_aws/collector.py
Expand Up @@ -47,7 +47,6 @@
global_resources: List[Type[AwsResource]] = (
cloudfront.resources
+ dynamodb.global_resources
+ ec2.global_resources
+ iam.resources
+ route53.resources
+ s3.resources
Expand Down
15 changes: 10 additions & 5 deletions plugins/aws/resoto_plugin_aws/resource/base.py
Expand Up @@ -391,7 +391,7 @@ def __init__(
self.client = client
self.executor = executor
self.name = f"AWS:{account.name}:{region.name}"
self.global_instance_types: Dict[str, Any] = global_instance_types or {}
self.global_instance_types: Dict[str, Any] = global_instance_types if global_instance_types is not None else {}
self.core_feedback = core_feedback

def submit_work(self, fn: Callable[..., None], *args: Any, **kwargs: Any) -> Future[Any]:
Expand Down Expand Up @@ -448,11 +448,16 @@ def resources_of(self, resource_type: Type[AwsResourceType]) -> List[AwsResource
return [n for n in self.graph.nodes if isinstance(n, resource_type)]

@lru_cache(maxsize=None)
def instance_type(self, instance_type: str) -> Optional[Any]:
if (global_type := self.global_instance_types.get(instance_type)) is None:
def instance_type(self, region: AwsRegion, instance_type: str) -> Optional[Any]:
if (it := self.global_instance_types.get(instance_type)) is None:
return None # instance type not found
price = AwsPricingPrice.instance_type_price(self.client, instance_type, self.region.safe_name)
return evolve(global_type, region=self.region, ondemand_cost=price.on_demand_price_usd if price else None)

price = AwsPricingPrice.instance_type_price(self.client.for_region(region.id), instance_type, region.safe_name)
result = evolve(it, region=self.region, ondemand_cost=price.on_demand_price_usd if price else None)
# add this instance type to the graph
self.add_node(result)
self.add_edge(region, node=result)
return result

@lru_cache(maxsize=None)
def volume_type(self, volume_type: str) -> Optional[Any]:
Expand Down
20 changes: 11 additions & 9 deletions plugins/aws/resoto_plugin_aws/resource/ec2.py
Expand Up @@ -351,6 +351,9 @@ def collect(cls: Type[AwsResource], json: List[Json], builder: GraphBuilder) ->
it = AwsEc2InstanceType.from_api(js)
# only store this information in the builder, not directly in the graph
# reason: pricing is region-specific - this is enriched in the builder on demand
# Only "used" instance type will be stored in the graph
# note: not all instance types are returned in any region.
# we collect instance types in all regions and make the data unique in the builder
builder.global_instance_types[it.safe_name] = it


Expand Down Expand Up @@ -1029,16 +1032,17 @@ def collect(cls: Type[AwsResource], json: List[Json], builder: GraphBuilder) ->
for instance_in in reservation["Instances"]:
mapped = bend(cls.mapping, instance_in)
instance = AwsEc2Instance.from_json(mapped)
# copy data from the instance type
if instance_type := builder.instance_type(instance.instance_type):
builder.add_node(instance_type, {})
instance.instance_cores = instance_type.instance_cores
instance.instance_memory = instance_type.instance_memory
builder.add_edge(instance_type, EdgeType.default, node=instance)
builder.add_node(instance, instance_in)

def connect_in_graph(self, builder: GraphBuilder, source: Json) -> None:
super().connect_in_graph(builder, source)
# connect instance type and copy values
# noinspection PyTypeChecker
if instance_type := builder.instance_type(self.region(), self.instance_type):
self.instance_cores = instance_type.instance_cores
self.instance_memory = instance_type.instance_memory
builder.add_edge(instance_type, EdgeType.default, node=self)

if self.instance_key_name:
builder.dependant_node(self, clazz=AwsEc2KeyPair, name=self.instance_key_name)
if vpc_id := source.get("VpcId"):
Expand Down Expand Up @@ -2386,10 +2390,8 @@ def called_mutator_apis(cls) -> List[AwsApiSpec]:

# endregion

global_resources: List[Type[AwsResource]] = [
AwsEc2InstanceType,
]
resources: List[Type[AwsResource]] = [
AwsEc2InstanceType,
AwsEc2ElasticIp,
AwsEc2Host,
AwsEc2Instance,
Expand Down
8 changes: 4 additions & 4 deletions plugins/aws/test/graphbuilder_test.py
Expand Up @@ -8,13 +8,13 @@

def test_instance_type(builder: GraphBuilder) -> None:
builder.global_instance_types["m4.large"] = AwsEc2InstanceType(id="m4.large")
m4l: AwsEc2InstanceType = builder.instance_type("m4.large") # type: ignore
assert m4l == builder.instance_type("m4.large")
m4l: AwsEc2InstanceType = builder.instance_type(builder.region, "m4.large") # type: ignore
assert m4l == builder.instance_type(builder.region, "m4.large")
assert m4l.ondemand_cost == 0.051
eu_builder = builder.for_region(AwsRegion(id="eu-central-1"))
m4l_eu: AwsEc2InstanceType = eu_builder.instance_type("m4.large") # type: ignore
m4l_eu: AwsEc2InstanceType = eu_builder.instance_type(eu_builder.region, "m4.large") # type: ignore
assert m4l != m4l_eu
assert m4l_eu == eu_builder.instance_type("m4.large")
assert m4l_eu == eu_builder.instance_type(eu_builder.region, "m4.large")
assert m4l_eu.ondemand_cost == 0.12


Expand Down

0 comments on commit 26973c3

Please sign in to comment.