diff --git a/cloudiscovery/__init__.py b/cloudiscovery/__init__.py
index 16a86c0..5d103f8 100644
--- a/cloudiscovery/__init__.py
+++ b/cloudiscovery/__init__.py
@@ -26,6 +26,7 @@
# pylint: disable=wrong-import-position
from provider.aws.command import aws_main
+from provider.ibm.command import ibm_main
from shared.parameters import generate_parser
@@ -54,14 +55,11 @@ def main():
if len(sys.argv) <= 1:
parser.print_help()
return
-
args = parser.parse_args()
-
if args.language is None or args.language not in AVAILABLE_LANGUAGES:
language = "en_US"
else:
language = args.language
-
# Diagram check
if "diagram" not in args:
diagram = False
@@ -77,7 +75,6 @@ def main():
# diagram version check
check_diagram_version(diagram)
-
# filters check
filters: List[Filterable] = []
if "filters" in args:
@@ -86,6 +83,10 @@ def main():
if args.command.startswith("aws"):
command = aws_main(args)
+ import_module = "provider.aws."
+ elif args.command.startswith("ibm"):
+ command = ibm_main(args)
+ import_module = "provider.ibm."
else:
raise NotImplementedError("Unknown command")
@@ -94,7 +95,7 @@ def main():
else:
services = []
- command.run(diagram, args.verbose, services, filters)
+ command.run(diagram, args.verbose, services, filters, import_module)
def check_diagram_version(diagram):
diff --git a/cloudiscovery/provider/aws/all/command.py b/cloudiscovery/provider/aws/all/command.py
index a954f48..f5fb5b0 100644
--- a/cloudiscovery/provider/aws/all/command.py
+++ b/cloudiscovery/provider/aws/all/command.py
@@ -16,12 +16,14 @@ def __init__(self, verbose, filters, session, region_name, services: List[str]):
class All(BaseAwsCommand):
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
for region in self.region_names:
self.init_region_cache(region)
@@ -32,7 +34,6 @@ def run(
region_name=region,
services=services,
)
-
command_runner = AwsCommandRunner(filters=filters)
command_runner.run(
provider="all",
@@ -41,4 +42,5 @@ def run(
title="AWS Resources - Region {}".format(region),
# pylint: disable=no-member
filename=options.resulting_file_name("all"),
+ import_module=import_module,
)
diff --git a/cloudiscovery/provider/aws/common_aws.py b/cloudiscovery/provider/aws/common_aws.py
index 661a142..96b11b4 100644
--- a/cloudiscovery/provider/aws/common_aws.py
+++ b/cloudiscovery/provider/aws/common_aws.py
@@ -151,12 +151,14 @@ def __init__(self, region_names, session, partition_code):
self.session: Session = session
self.partition_code: str = partition_code
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
raise NotImplementedError()
@@ -197,22 +199,22 @@ def resource_tags(resource_data: dict) -> List[Filterable]:
def resource_tags_from_tuples(tuples: List[Dict[str, str]]) -> List[Filterable]:
"""
- List of key-value tuples that store tags, syntax:
- [
- {
- 'Key': 'string',
- 'Value': 'string',
- ...
- },
- ]
- OR
- [
- {
- 'key': 'string',
- 'value': 'string',
- ...
- },
- ]
+ List of key-value tuples that store tags, syntax:
+ [
+ {
+ 'Key': 'string',
+ 'Value': 'string',
+ ...
+ },
+ ]
+ OR
+ [
+ {
+ 'key': 'string',
+ 'value': 'string',
+ ...
+ },
+ ]
"""
result = []
for tuple_elem in tuples:
@@ -225,10 +227,10 @@ def resource_tags_from_tuples(tuples: List[Dict[str, str]]) -> List[Filterable]:
def resource_tags_from_dict(tags: Dict[str, str]) -> List[Filterable]:
"""
- List of key-value dict that store tags, syntax:
- {
- 'string': 'string'
- }
+ List of key-value dict that store tags, syntax:
+ {
+ 'string': 'string'
+ }
"""
result = []
for key, value in tags.items():
@@ -255,8 +257,10 @@ def generate_session(profile_name, region_name):
return boto3.Session(profile_name=profile_name, region_name=region_name)
# pylint: disable=broad-except
except Exception as e:
- message = "You must configure awscli before use this script.\nError: {0}".format(
- str(e)
+ message = (
+ "You must configure awscli before use this script.\nError: {0}".format(
+ str(e)
+ )
)
exit_critical(message)
diff --git a/cloudiscovery/provider/aws/iot/command.py b/cloudiscovery/provider/aws/iot/command.py
index 11e6b98..b5f4a86 100644
--- a/cloudiscovery/provider/aws/iot/command.py
+++ b/cloudiscovery/provider/aws/iot/command.py
@@ -33,12 +33,14 @@ def __init__(self, thing_name, region_names, session, partition_code):
super().__init__(region_names, session, partition_code)
self.thing_name = thing_name
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
command_runner = AwsCommandRunner(filters)
@@ -67,6 +69,7 @@ def run(
diagram_builder=diagram_builder,
title="AWS IoT Resources - Region {}".format(region_name),
filename=thing_options.resulting_file_name("iot"),
+ import_module=import_module,
)
else:
things = dict()
@@ -94,4 +97,5 @@ def run(
filename=thing_options.resulting_file_name(
self.thing_name + "_iot"
),
+ import_module=import_module,
)
diff --git a/cloudiscovery/provider/aws/limit/command.py b/cloudiscovery/provider/aws/limit/command.py
index ecfe43d..5b656f2 100644
--- a/cloudiscovery/provider/aws/limit/command.py
+++ b/cloudiscovery/provider/aws/limit/command.py
@@ -147,12 +147,14 @@ def init_globalaws_limits_cache(self, region, services, options: LimitOptions):
session=self.session, region=region, services=services, options=options
).init_globalaws_limits_cache()
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
if not services:
services = []
@@ -182,4 +184,5 @@ def run(
title="AWS Limits - Region {}".format(region),
# pylint: disable=no-member
filename=limit_options.resulting_file_name("limit"),
+ import_module=import_module,
)
diff --git a/cloudiscovery/provider/aws/policy/command.py b/cloudiscovery/provider/aws/policy/command.py
index 8bf28aa..a034c9b 100644
--- a/cloudiscovery/provider/aws/policy/command.py
+++ b/cloudiscovery/provider/aws/policy/command.py
@@ -13,12 +13,14 @@ def __init__(self, verbose, filters, session, region_name):
class Policy(BaseAwsCommand):
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
for region in self.region_names:
self.init_region_cache(region)
@@ -40,4 +42,5 @@ def run(
diagram_builder=diagram,
title="AWS IAM Policies - Region {}".format(region),
filename=options.resulting_file_name("policy"),
+ import_module=import_module,
)
diff --git a/cloudiscovery/provider/aws/security/command.py b/cloudiscovery/provider/aws/security/command.py
index 29ecf39..5bb1c57 100644
--- a/cloudiscovery/provider/aws/security/command.py
+++ b/cloudiscovery/provider/aws/security/command.py
@@ -14,7 +14,12 @@ class SecurityOptions(BaseAwsOptions, BaseOptions):
# pylint: disable=too-many-arguments
def __init__(
- self, verbose: bool, filters: List[Filterable], session, region_name, commands,
+ self,
+ verbose: bool,
+ filters: List[Filterable],
+ session,
+ region_name,
+ commands,
):
BaseAwsOptions.__init__(self, session, region_name)
BaseOptions.__init__(self, verbose, filters)
@@ -43,12 +48,14 @@ def __init__(self, region_names, session, commands, partition_code):
super().__init__(region_names, session, partition_code)
self.commands = commands
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
for region in self.region_names:
@@ -68,4 +75,5 @@ def run(
title="AWS Security - Region {}".format(region),
# pylint: disable=no-member
filename=security_options.resulting_file_name("security"),
+ import_module=import_module,
)
diff --git a/cloudiscovery/provider/aws/vpc/command.py b/cloudiscovery/provider/aws/vpc/command.py
index 12768f8..a088429 100644
--- a/cloudiscovery/provider/aws/vpc/command.py
+++ b/cloudiscovery/provider/aws/vpc/command.py
@@ -62,14 +62,15 @@ def check_vpc(vpc_options: VpcOptions):
)
print(message)
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
- # pylint: disable=too-many-branches
command_runner = AwsCommandRunner(filters)
for region in self.region_names:
@@ -100,6 +101,7 @@ def run(
diagram_builder=diagram_builder,
title="AWS VPC {} Resources - Region {}".format(vpc_id, region),
filename=vpc_options.resulting_file_name(vpc_id + "_vpc"),
+ import_module=import_module,
)
else:
vpc_options = VpcOptions(
@@ -123,6 +125,7 @@ def run(
self.vpc_id, region
),
filename=vpc_options.resulting_file_name(self.vpc_id + "_vpc"),
+ import_module=import_module,
)
diff --git a/cloudiscovery/provider/ibm/__init__.py b/cloudiscovery/provider/ibm/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/cloudiscovery/provider/ibm/command.py b/cloudiscovery/provider/ibm/command.py
new file mode 100644
index 0000000..47d2588
--- /dev/null
+++ b/cloudiscovery/provider/ibm/command.py
@@ -0,0 +1,40 @@
+from provider.ibm.vpc.command import Vpc
+from shared.common import (
+ exit_critical,
+ BaseCommand,
+)
+
+DEFAULT_REGION = "us-south"
+
+
+def ibm_main(args) -> BaseCommand:
+
+ # Check if verbose mode is enabled
+
+ # ibm profile check
+ region_name = args.region_name
+
+ if "region_name" not in args:
+ region_name = [DEFAULT_REGION]
+
+ if "url" not in args:
+ url = "https://us-south.iaas.cloud.ibm.com"
+
+ if "threshold" in args:
+ if args.threshold is not None:
+ if args.threshold.isdigit() is False:
+ exit_critical("Threshold must be between 0 and 100")
+ else:
+ if int(args.threshold) < 0 or int(args.threshold) > 100:
+ exit_critical("Threshold must be between 0 and 100")
+
+ if args.command == "ibm-vpc":
+ command = Vpc(
+ vpc_id=args.vpc_id,
+ apikey=args.api_key,
+ region=region_name,
+ url=url,
+ )
+ else:
+ raise NotImplementedError("Unknown command")
+ return command
diff --git a/cloudiscovery/provider/ibm/common_ibm.py b/cloudiscovery/provider/ibm/common_ibm.py
new file mode 100644
index 0000000..804e705
--- /dev/null
+++ b/cloudiscovery/provider/ibm/common_ibm.py
@@ -0,0 +1,210 @@
+from typing import List, Dict, Optional
+
+
+from cachetools import TTLCache
+
+from shared.command import CommandRunner
+from shared.common import (
+ ResourceCache,
+ Filterable,
+ BaseCommand,
+)
+from ibm_vpc import VpcV1
+from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
+from ibm_cloud_sdk_core import ApiException
+
+SUBNET_CACHE = TTLCache(maxsize=1024, ttl=60)
+
+
+def describe_subnet(service, subnet_ids):
+ if not isinstance(subnet_ids, list):
+ subnet_ids = [subnet_ids]
+
+ if str(subnet_ids) in SUBNET_CACHE:
+ return SUBNET_CACHE[str(subnet_ids)]
+
+ try:
+ subnets = service.list_subnets()
+ SUBNET_CACHE[str(subnet_ids)] = subnets
+ return subnets
+ except ApiException as e:
+ print("List Subnets failed with status code " + str(e.code) + ": " + e.message)
+
+
+class BaseIbmOptions:
+ region: str
+ apikey: str
+ service: VpcV1
+
+ def __init__(self, apikey, region):
+ """
+ Base IBM options
+
+ :param session:
+ :param region_name:
+ """
+ self.region = region
+ self.apikey = apikey
+ authenticator = IAMAuthenticator(self.apikey)
+ self.service = VpcV1(authenticator=authenticator)
+ vpc_url = "https://" + region + ".iaas.cloud.ibm.com"
+ self.service.set_service_url(vpc_url)
+ self.service = VpcV1("2020-04-10", authenticator=authenticator)
+
+ def client(self):
+ return self.service
+
+
+class GlobalParameters:
+ def __init__(self, apikey, region: str):
+ self.region = region
+ self.apikey = apikey
+ authenticator = IAMAuthenticator(self.apikey)
+ self.service = VpcV1(authenticator=authenticator)
+ vpc_url = "https://" + region + ".iaas.cloud.ibm.com"
+ self.service.set_service_url(vpc_url)
+ self.service = VpcV1("2020-04-10", authenticator=authenticator)
+ self.cache = ResourceCache()
+
+
+class BaseIbmCommand(BaseCommand):
+ region: str
+ apikey: str
+ url: str
+ service: VpcV1
+
+ def __init__(self, region, apikey, url):
+ """
+ Base class for discovery command
+
+ :param region:
+ :param apikey:
+ """
+ self.region = region
+ self.apikey = apikey
+ authenticator = IAMAuthenticator(self.apikey)
+ self.service = VpcV1(authenticator=authenticator)
+ vpc_url = url
+ self.service.set_service_url(vpc_url)
+ self.service = VpcV1("2020-04-10", authenticator=authenticator)
+
+ # pylint: disable=too-many-arguments
+ def run(
+ self,
+ diagram: bool,
+ verbose: bool,
+ services: List[str],
+ filters: List[Filterable],
+ import_module: str,
+ ):
+ raise NotImplementedError()
+
+
+def resource_tags(resource_data: dict) -> List[Filterable]:
+ if isinstance(resource_data, str):
+ return []
+
+ if "Tags" in resource_data:
+ tags_input = resource_data["Tags"]
+ elif "tags" in resource_data:
+ tags_input = resource_data["tags"]
+ elif "TagList" in resource_data:
+ tags_input = resource_data["TagList"]
+ elif "TagSet" in resource_data:
+ tags_input = resource_data["TagSet"]
+ else:
+ tags_input = None
+
+ tags = []
+ if isinstance(tags_input, list):
+ tags = resource_tags_from_tuples(tags_input)
+ elif isinstance(tags_input, dict):
+ tags = resource_tags_from_dict(tags_input)
+
+ return tags
+
+
+def resource_tags_from_tuples(tuples: List[Dict[str, str]]) -> List[Filterable]:
+ """
+ List of key-value tuples that store tags, syntax:
+ [
+ {
+ 'Key': 'string',
+ 'Value': 'string',
+ ...
+ },
+ ]
+ OR
+ [
+ {
+ 'key': 'string',
+ 'value': 'string',
+ ...
+ },
+ ]
+ """
+ result = []
+ for tuple_elem in tuples:
+ if "Key" in tuple_elem and "Value" in tuple_elem:
+ result.append(Filterable(key=tuple_elem["Key"], value=tuple_elem["Value"]))
+ elif "key" in tuple_elem and "value" in tuple_elem:
+ result.append(Filterable(key=tuple_elem["key"], value=tuple_elem["value"]))
+ return result
+
+
+def resource_tags_from_dict(tags: Dict[str, str]) -> List[Filterable]:
+ """
+ List of key-value dict that store tags, syntax:
+ {
+ 'string': 'string'
+ }
+ """
+ result = []
+ for key, value in tags.items():
+ result.append(Filterable(key=key, value=value))
+ return result
+
+
+# pylint: disable=unsubscriptable-object
+def get_name_tag(d) -> Optional[str]:
+ return get_tag(d, "Name")
+
+
+# pylint: disable=unsubscriptable-object
+def get_tag(d, tag_name) -> Optional[str]:
+ for k, v in d.items():
+ if k in ("Tags", "TagList"):
+ for value in v:
+ if value["Key"] == tag_name:
+ return value["Value"]
+
+ return None
+
+
+def get_paginator(client, operation_name, resource_type, filters=None):
+ # Checking if can paginate
+ if client.can_paginate(operation_name):
+ paginator = client.get_paginator(operation_name)
+ if resource_type == "aws_iam_policy":
+ pages = paginator.paginate(
+ Scope="Local"
+ ) # hack to list only local IAM policies - aws_all
+ else:
+ if filters:
+ pages = paginator.paginate(**filters)
+ else:
+ pages = paginator.paginate()
+ else:
+ return False
+
+ return pages
+
+
+class IbmCommandRunner(CommandRunner):
+ def __init__(self, filters: List[Filterable] = None):
+ """
+ IBM command execution
+
+ :param filters:
+ """
+ super().__init__("ibm", filters)
diff --git a/cloudiscovery/provider/ibm/vpc/__init__.py b/cloudiscovery/provider/ibm/vpc/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/cloudiscovery/provider/ibm/vpc/command.py b/cloudiscovery/provider/ibm/vpc/command.py
new file mode 100644
index 0000000..65daeff
--- /dev/null
+++ b/cloudiscovery/provider/ibm/vpc/command.py
@@ -0,0 +1,200 @@
+from typing import List
+
+from ipaddress import ip_network
+
+from provider.ibm.common_ibm import BaseIbmOptions, BaseIbmCommand, IbmCommandRunner
+from provider.ibm.vpc.diagram import VpcDiagram
+from shared.common import (
+ ResourceDigest,
+ VPCE_REGEX,
+ SOURCE_IP_ADDRESS_REGEX,
+ Filterable,
+ BaseOptions,
+)
+from shared.diagram import NoDiagram, BaseDiagram
+from ibm_vpc import VpcV1
+from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
+
+
+class VpcOptions(BaseIbmOptions, BaseOptions):
+ vpc_id: str
+
+ # pylint: disable=too-many-arguments
+ def __init__(
+ self, verbose: bool, filters: List[Filterable], apikey, region, vpc_id
+ ):
+ BaseIbmOptions.__init__(self, apikey, region)
+ BaseOptions.__init__(self, verbose, filters)
+ self.vpc_id = vpc_id
+
+ def vpc_digest(self):
+ return ResourceDigest(id=self.vpc_id, type="ibm_vpc")
+
+ def resulting_file_name(self):
+ return "{}_{}".format(self.vpc_id, self.region)
+
+
+class Vpc(BaseIbmCommand):
+ vpc_id: str
+ region: str
+ apikey: str
+ service: VpcV1
+
+ # pylint: disable=too-many-arguments
+ def __init__(self, region, apikey, vpc_id, url):
+ """
+ VPC command
+
+ :param vpc_id:
+ :param region:
+ :param apikey:
+ """
+ super().__init__(region, apikey, url)
+ self.vpc_id = vpc_id
+ self.apikey = apikey
+ self.region = region
+ authenticator = IAMAuthenticator(self.apikey)
+ self.service = VpcV1(authenticator=authenticator)
+ vpc_url = url
+ self.service.set_service_url(vpc_url)
+
+ def check_vpc(self, service: VpcV1):
+ response = self.service.get_vpc(self.vpc_id)
+
+ message = "------------------------------------------------------\n"
+ message = message + "VPC: {} - {}\nName: {}".format(
+ self.vpc_id,
+ self.region,
+ response["name"],
+ )
+ print(message)
+
+ #pylint: disable=too-many-arguments
+ def run(
+ self,
+ diagram: bool,
+ verbose: bool,
+ services: List[str],
+ filters: List[Filterable],
+ import_module: str,
+ ):
+ command_runner = IbmCommandRunner(filters)
+
+ # if vpc is none, get all vpcs and check
+ if self.vpc_id is None:
+ vpcs = self.service.list_vpcs().get_result()["vpcs"]
+ for data in vpcs["Vpcs"]:
+ vpc_id = data["id"]
+ vpc_options = VpcOptions(
+ verbose=verbose,
+ filters=filters,
+ apikey=self.apikey,
+ region=self.region,
+ vpc_id=vpc_id,
+ )
+ self.check_vpc(vpc_options)
+ diagram_builder: BaseDiagram
+ if diagram:
+ diagram_builder = VpcDiagram(vpc_id=vpc_id)
+ else:
+ diagram_builder = NoDiagram()
+ command_runner.run(
+ provider="vpc",
+ options=vpc_options,
+ diagram_builder=diagram_builder,
+ title="IBM VPC {} Resources - Region {}".format(
+ vpc_id, self.region
+ ),
+ filename=vpc_options.resulting_file_name(),
+ import_module=import_module,
+ )
+ else:
+ vpc_options = VpcOptions(
+ verbose=verbose,
+ filters=filters,
+ apikey=self.apikey,
+ region=self.region,
+ vpc_id=self.vpc_id,
+ )
+
+ # self.check_vpc(vpc_options)
+ if diagram:
+ diagram_builder = VpcDiagram(vpc_id=self.vpc_id)
+ else:
+ diagram_builder = NoDiagram()
+ command_runner.run(
+ provider="vpc",
+ options=vpc_options,
+ diagram_builder=diagram_builder,
+ title="IBM VPC {} Resources - Region {}".format(
+ self.vpc_id, self.region
+ ),
+ filename=vpc_options.resulting_file_name(),
+ import_module=import_module,
+ )
+
+
+# pylint: disable=too-many-branches
+def check_ipvpc_inpolicy(document, vpc_options: VpcOptions):
+ document = document.replace("\\", "").lower()
+
+ # Checking if VPC is inside document, it's a 100% true information
+ # pylint: disable=no-else-return
+ if vpc_options.vpc_id in document:
+ return "direct VPC reference"
+ else:
+ # Vpc_id not found, trying to discover if it's a potencial subnet IP or VPCE is allowed
+ if "ibm:sourcevpce" in document:
+
+ # Get VPCE found
+ ibm_sourcevpces = []
+ for vpce_tuple in VPCE_REGEX.findall(document):
+ ibm_sourcevpces.append(vpce_tuple[1])
+
+ # Get all VPCE of this VPC
+ ec2 = vpc_options.client("ec2")
+
+ filters = [{"Name": "vpc-id", "Values": [vpc_options.vpc_id]}]
+
+ vpc_endpoints = ec2.describe_vpc_endpoints(Filters=filters)
+
+ # iterate VPCEs found found
+ if len(vpc_endpoints["VpcEndpoints"]) > 0:
+ matching_vpces = []
+ # Iterate VPCE to match vpce in Policy Document
+ for data in vpc_endpoints["VpcEndpoints"]:
+ if data["VpcEndpointId"] in ibm_sourcevpces:
+ matching_vpces.append(data["VpcEndpointId"])
+ return "VPC Endpoint(s): " + (", ".join(matching_vpces))
+
+ if "ibm:sourceip" in document:
+
+ # Get ip found
+ ibm_sourceips = []
+ for vpce_tuple in SOURCE_IP_ADDRESS_REGEX.findall(document):
+ ibm_sourceips.append(vpce_tuple[1])
+ # Get subnets cidr block
+ ec2 = vpc_options.client("ec2")
+
+ filters = [{"Name": "vpc-id", "Values": [vpc_options.vpc_id]}]
+
+ subnets = ec2.describe_subnets(Filters=filters)
+ overlapping_subnets = []
+ # iterate ips found
+ for ipfound in ibm_sourceips:
+
+ # Iterate subnets to match ipaddress
+ for subnet in list(subnets["Subnets"]):
+ ipfound = ip_network(ipfound)
+ network_addres = ip_network(subnet["CidrBlock"])
+
+ if ipfound.overlaps(network_addres):
+ overlapping_subnets.append(
+ "{} ({})".format(str(network_addres), subnet["SubnetId"])
+ )
+ if len(overlapping_subnets) != 0:
+ return "source IP(s): {} -> subnet CIDR(s): {}".format(
+ ", ".join(ibm_sourceips), ", ".join(overlapping_subnets)
+ )
+
+ return False
diff --git a/cloudiscovery/provider/ibm/vpc/diagram.py b/cloudiscovery/provider/ibm/vpc/diagram.py
new file mode 100644
index 0000000..22c6113
--- /dev/null
+++ b/cloudiscovery/provider/ibm/vpc/diagram.py
@@ -0,0 +1,248 @@
+from typing import List, Dict, Optional
+
+from shared.common import ResourceEdge, Resource, ResourceDigest
+from shared.diagram import add_resource_to_group, VPCDiagramsNetDiagram
+
+PUBLIC_SUBNET = "{public subnet}"
+PRIVATE_SUBNET = "{private subnet}"
+ASG_EC2_AGGREGATE_PREFIX = "asg_ec2_aggregate_"
+ASG_ECS_INSTANCE_AGGREGATE_PREFIX = "asg_ecs_instance_aggregate_"
+
+# pylint: disable=unsubscriptable-object
+def to_node_get_aggregated(
+ resource_relation: ResourceEdge, resources: List[Resource]
+) -> Optional[Resource]:
+ for resource in resources:
+ if (
+ " subnet}" in resource.digest.id
+ or ASG_EC2_AGGREGATE_PREFIX in resource.digest.id
+ or ASG_ECS_INSTANCE_AGGREGATE_PREFIX in resource.digest.id
+ ):
+ if resource_relation.to_node.id in resource.details:
+ return resource
+ return None
+
+
+# pylint: disable=unsubscriptable-object
+def from_node_get_aggregated(
+ resource_relation: ResourceEdge, resources: List[Resource]
+) -> Optional[Resource]:
+ for resource in resources:
+ if (
+ " subnet}" in resource.digest.id
+ or ASG_EC2_AGGREGATE_PREFIX in resource.digest.id
+ or ASG_ECS_INSTANCE_AGGREGATE_PREFIX in resource.digest.id
+ ):
+ if resource_relation.from_node.id in resource.details:
+ return resource
+ return None
+
+
+def aggregate_subnets(groups, group_type, group_name):
+ if group_type in groups:
+ subnet_ids = []
+ for subnet in groups[group_type]:
+ subnet_ids.append(subnet.digest.id)
+ groups[""].append(
+ Resource(
+ digest=ResourceDigest(id=group_type, type="ibm_subnet"),
+ name=group_name + ", ".join(subnet_ids),
+ details=", ".join(subnet_ids),
+ )
+ )
+
+
+# pylint: disable=unsubscriptable-object
+def get_ec2_asg(
+ initial_resource_relations: List[ResourceEdge], ec2_digest: Optional[ResourceDigest]
+) -> Optional[str]:
+ if ec2_digest is None:
+ return None
+ for relation in initial_resource_relations:
+ if (
+ relation.from_node == ec2_digest
+ and relation.to_node.type == "ibm_autoscaling_group"
+ ):
+ return relation.to_node.id
+ return None
+
+
+# pylint: disable=unsubscriptable-object
+def get_ecs_ec2(
+ initial_resource_relations: List[ResourceEdge], ecs_instance_digest: ResourceDigest
+) -> Optional[ResourceDigest]:
+ for relation in initial_resource_relations:
+ if (
+ relation.from_node == ecs_instance_digest
+ and relation.to_node.type == "ibm_instance"
+ ):
+ return relation.to_node
+ return None
+
+
+def aggregate_asg_groups(
+ groups: Dict[str, List[Resource]], prefix: str, aggregate_name: str
+):
+ for group_name, group_elements in groups.items():
+ if group_name.startswith(prefix):
+ agg_type = "none"
+ elem_ids = []
+ for element in group_elements:
+ agg_type = element.digest.type
+ elem_ids.append(element.digest.id)
+ agg_resource = Resource(
+ digest=ResourceDigest(id=group_name, type=agg_type),
+ name=aggregate_name + "({})".format(len(group_elements)),
+ details=",".join(elem_ids),
+ )
+ add_resource_to_group(groups, "", agg_resource)
+
+
+class VpcDiagram(VPCDiagramsNetDiagram):
+ def __init__(self, vpc_id: str):
+ """
+ VPC diagram
+
+ :param vpc_id:
+ """
+ super().__init__()
+ self.vpc_id = vpc_id
+
+ # pylint: disable=too-many-branches
+ def group_by_group(
+ self, resources: List[Resource], initial_resource_relations: List[ResourceEdge]
+ ) -> Dict[str, List[Resource]]:
+ groups: Dict[str, List[Resource]] = {"": []}
+ # pylint: disable=too-many-nested-blocks
+ for resource in resources:
+ if resource.digest.type == "ibm_subnet":
+ associated_tables = []
+ for relation in initial_resource_relations:
+ if relation.from_node.type == "ibm_route_table" and (
+ relation.to_node == resource.digest
+ or (
+ relation.to_node.type == "ibm_vpc"
+ and relation.to_node.id == self.vpc_id
+ )
+ ):
+ for resource_2 in resources:
+ if resource_2.digest == relation.from_node:
+ associated_tables.append(resource_2)
+ is_public = False
+ for associated_table in associated_tables:
+ if "public: True" in associated_table.details:
+ is_public = True
+ if is_public:
+ add_resource_to_group(groups, PUBLIC_SUBNET, resource)
+ else:
+ add_resource_to_group(groups, PRIVATE_SUBNET, resource)
+ elif resource.digest.type == "ibm_instance":
+ related_asg = get_ec2_asg(initial_resource_relations, resource.digest)
+ if related_asg is not None:
+ add_resource_to_group(
+ groups, ASG_EC2_AGGREGATE_PREFIX + related_asg, resource
+ )
+ else:
+ add_resource_to_group(groups, "", resource)
+ elif resource.digest.type == "ibm_ecs_cluster":
+ related_ec2 = get_ecs_ec2(initial_resource_relations, resource.digest)
+ related_asg = get_ec2_asg(initial_resource_relations, related_ec2)
+ if related_asg is not None:
+ add_resource_to_group(
+ groups,
+ ASG_ECS_INSTANCE_AGGREGATE_PREFIX + related_asg,
+ resource,
+ )
+ else:
+ add_resource_to_group(groups, "", resource)
+ else:
+ add_resource_to_group(groups, "", resource)
+
+ aggregate_asg_groups(groups, ASG_EC2_AGGREGATE_PREFIX, "EC2 instances for ASG ")
+ aggregate_asg_groups(
+ groups, ASG_ECS_INSTANCE_AGGREGATE_PREFIX, "EC2 instances for ECS cluster "
+ )
+
+ aggregate_subnets(groups, PUBLIC_SUBNET, "Public subnets: ")
+ aggregate_subnets(groups, PRIVATE_SUBNET, "Private subnets: ")
+
+ return {"": groups[""]}
+
+ def process_relationships(
+ self,
+ grouped_resources: Dict[str, List[Resource]],
+ resource_relations: List[ResourceEdge],
+ ) -> List[ResourceEdge]:
+ relations: List[ResourceEdge] = []
+ for resource in grouped_resources[""]:
+ if resource.digest.type == "ibm_subnet":
+ """
+ if (
+ resource.digest.id == PUBLIC_SUBNET
+ or resource.digest.id == PRIVATE_SUBNET
+ ):
+ """
+ relations.append(
+ ResourceEdge(
+ from_node=resource.digest,
+ to_node=ResourceDigest(id=self.vpc_id, type="ibm_vpc"),
+ )
+ )
+ elif ASG_EC2_AGGREGATE_PREFIX in resource.digest.id:
+ prefix_len = len(ASG_EC2_AGGREGATE_PREFIX)
+ asg_name = resource.digest.id[prefix_len:]
+ relations.append(
+ ResourceEdge(
+ from_node=ResourceDigest(
+ id=resource.digest.id, type="ibm_instance"
+ ),
+ to_node=ResourceDigest(
+ id=asg_name, type="ibm_autoscaling_group"
+ ),
+ )
+ )
+ elif ASG_ECS_INSTANCE_AGGREGATE_PREFIX in resource.digest.id:
+ prefix_len = len(ASG_ECS_INSTANCE_AGGREGATE_PREFIX)
+ asg_name = resource.digest.id[prefix_len:]
+ relations.append(
+ ResourceEdge(
+ from_node=ResourceDigest(
+ id=resource.digest.id, type="ibm_ecs_cluster"
+ ),
+ to_node=ResourceDigest(
+ id=asg_name, type="ibm_autoscaling_group"
+ ),
+ )
+ )
+ for resource_relation in resource_relations:
+ aggregate_digest_to_node = to_node_get_aggregated(
+ resource_relation, grouped_resources[""]
+ )
+ aggregate_digest_from_node = from_node_get_aggregated(
+ resource_relation, grouped_resources[""]
+ )
+ if aggregate_digest_to_node and aggregate_digest_from_node:
+ relations.append(
+ ResourceEdge(
+ from_node=aggregate_digest_from_node.digest,
+ to_node=aggregate_digest_to_node.digest,
+ )
+ )
+ elif aggregate_digest_to_node:
+ relations.append(
+ ResourceEdge(
+ from_node=resource_relation.from_node,
+ to_node=aggregate_digest_to_node.digest,
+ )
+ )
+ elif aggregate_digest_from_node:
+ relations.append(
+ ResourceEdge(
+ from_node=aggregate_digest_from_node.digest,
+ to_node=resource_relation.to_node,
+ )
+ )
+ else:
+ relations.append(resource_relation)
+
+ return relations
diff --git a/cloudiscovery/provider/ibm/vpc/resource/__init__.py b/cloudiscovery/provider/ibm/vpc/resource/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/cloudiscovery/provider/ibm/vpc/resource/network.py b/cloudiscovery/provider/ibm/vpc/resource/network.py
new file mode 100644
index 0000000..4424bcd
--- /dev/null
+++ b/cloudiscovery/provider/ibm/vpc/resource/network.py
@@ -0,0 +1,235 @@
+from typing import List
+
+from provider.ibm.common_ibm import resource_tags
+from provider.ibm.vpc.command import VpcOptions
+from ibm_cloud_sdk_core import ApiException
+from shared.common import (
+ ResourceProvider,
+ Resource,
+ message_handler,
+ ResourceDigest,
+ ResourceEdge,
+)
+from shared.error_handler import exception
+
+
+class RouteTable(ResourceProvider):
+ def __init__(self, vpc_options: VpcOptions):
+ """
+ Route table
+
+ :param vpc_options:
+ """
+ super().__init__()
+ self.vpc_options = vpc_options
+
+ @exception
+ def get_resources(self) -> List[Resource]:
+
+ service = self.vpc_options.service
+ resources_found = []
+ list_tables = service.list_vpc_routing_tables(
+ self.vpc_options.vpc_id
+ ).get_result()["routing_tables"]
+ # Iterate to get all route table filtered
+ for route_table in list_tables:
+ name = route_table["id"]
+ is_default = route_table["is_default"]
+ table_digest = ResourceDigest(id=route_table["id"], type="ibm_route_table")
+
+ self.relations_found.append(
+ ResourceEdge(
+ from_node=table_digest,
+ to_node=self.vpc_options.vpc_digest(),
+ )
+ )
+
+ list_routes = route_table["routes"]
+ for response in list_routes:
+ digest = ResourceDigest(id=response["id"], type="ibm_route")
+
+ resources_found.append(
+ Resource(
+ digest=digest,
+ name=response["name"],
+ details="",
+ group="network",
+ tags=resource_tags(response),
+ )
+ )
+ self.relations_found.append(
+ ResourceEdge(
+ from_node=digest,
+ to_node=table_digest,
+ )
+ )
+
+ list_subnets = route_table["subnets"]
+
+ for subnet in list_subnets:
+ digest = ResourceDigest(id=subnet["id"], type="ibm_subnet")
+ resources_found.append(
+ Resource(
+ digest=digest,
+ name=subnet["name"],
+ details="",
+ group="network",
+ tags=resource_tags(subnet),
+ )
+ )
+ self.relations_found.append(
+ ResourceEdge(
+ from_node=table_digest,
+ to_node=digest,
+ )
+ )
+ is_public = False
+ try:
+ response = service.get_subnet_public_gateway(id=subnet["id"])
+ if response is not None:
+ if response["id"] is not None:
+ is_public = True
+ pgw_digest = ResourceDigest(
+ id=response["id"], type="ibm_public_gateway"
+ )
+ resources_found.append(
+ Resource(
+ digest=pgw_digest,
+ name=response["name"],
+ details="public: {}".format(is_public),
+ group="network",
+ tags=resource_tags(response),
+ )
+ )
+ self.relations_found.append(
+ ResourceEdge(
+ from_node=pgw_digest,
+ to_node=digest,
+ )
+ )
+ except ApiException:
+ print("No public gateway for subnet id " + subnet["id"])
+
+ resources_found.append(
+ Resource(
+ digest=table_digest,
+ name=name,
+ details="default: {}, public: {}".format(is_default, is_public),
+ group="network",
+ tags=resource_tags(route_table),
+ )
+ )
+ return resources_found
+
+
+class VPC(ResourceProvider):
+ def __init__(self, vpc_options: VpcOptions):
+ """
+ Vpc
+
+ :param vpc_options:
+ """
+ super().__init__()
+ self.vpc_options = vpc_options
+
+ @exception
+ def get_resources(self) -> List[Resource]:
+ # service = self.vpc_options.service
+ # vpc_response = service.get_vpc(self.vpc_options.vpc_id)
+ return [
+ Resource(
+ digest=self.vpc_options.vpc_digest(),
+ name=self.vpc_options.vpc_id,
+ tags="",
+ )
+ ]
+
+
+class NACL(ResourceProvider):
+ def __init__(self, vpc_options: VpcOptions):
+
+ # Nacl
+
+ # :param vpc_options:
+
+ super().__init__()
+ self.vpc_options = vpc_options
+
+ @exception
+ def get_resources(self) -> List[Resource]:
+
+ service = self.vpc_options.service
+
+ resources_found = []
+
+ response = service.get_vpc_default_network_acl(
+ id=self.vpc_options.vpc_id
+ ).get_result()
+ if self.vpc_options.verbose:
+ message_handler("Collecting data from NACLs...", "HEADER")
+
+ nacl_digest = ResourceDigest(id=response["id"], type="ibm_network_acl")
+ subnet_ids = []
+ for subnet in response["subnets"]:
+ subnet_ids.append(subnet["id"])
+ self.relations_found.append(
+ ResourceEdge(
+ from_node=nacl_digest,
+ to_node=ResourceDigest(id=subnet["id"], type="ibm_subnet"),
+ )
+ )
+
+ name = response["name"]
+
+ resources_found.append(
+ Resource(
+ digest=nacl_digest,
+ name=name,
+ details="NACL using Subnets {}".format(", ".join(subnet_ids)),
+ group="network",
+ tags=resource_tags(response),
+ )
+ )
+
+ return resources_found
+
+
+class SECURITYGROUP(ResourceProvider):
+ def __init__(self, vpc_options: VpcOptions):
+
+ # Security group
+
+ # :param vpc_options:
+
+ super().__init__()
+ self.vpc_options = vpc_options
+
+ @exception
+ def get_resources(self) -> List[Resource]:
+ service = self.vpc_options.service
+ response = service.list_security_groups(
+ vpc_id=self.vpc_options.vpc_id
+ ).get_result()
+ resources_found = []
+
+ if self.vpc_options.verbose:
+ message_handler("Collecting data from Security Groups...", "HEADER")
+
+ for data in response["security_groups"]:
+ group_digest = ResourceDigest(id=data["id"], type="ibm_security_group")
+ resources_found.append(
+ Resource(
+ digest=group_digest,
+ name=data["name"],
+ details="",
+ group="network",
+ tags=resource_tags(data),
+ )
+ )
+ self.relations_found.append(
+ ResourceEdge(
+ from_node=group_digest, to_node=self.vpc_options.vpc_digest()
+ )
+ )
+
+ return resources_found
diff --git a/cloudiscovery/shared/command.py b/cloudiscovery/shared/command.py
index 2c303c6..876e495 100644
--- a/cloudiscovery/shared/command.py
+++ b/cloudiscovery/shared/command.py
@@ -37,6 +37,7 @@ def run(
diagram_builder: BaseDiagram,
title: str,
filename: str,
+ import_module: str,
):
"""
Executes a command.
@@ -63,7 +64,8 @@ def run(
# Load and call all run check
for nameclass, cls in inspect.getmembers(
importlib.import_module(
- "provider.aws."
+ import_module
+ #"provider.aws."
+ provider.replace("/", ".")
+ ".resource."
+ module
@@ -90,7 +92,6 @@ def run(
all_resources.extend(provider_result[0])
if provider_result[1] is not None:
resource_relations.extend(provider_result[1])
-
unique_resources_dict: Dict[ResourceDigest, Resource] = dict()
for resource in all_resources:
unique_resources_dict[resource.digest] = resource
diff --git a/cloudiscovery/shared/common.py b/cloudiscovery/shared/common.py
index d1ed5cb..f00b10d 100644
--- a/cloudiscovery/shared/common.py
+++ b/cloudiscovery/shared/common.py
@@ -239,12 +239,14 @@ def parse_filters(arg_filters) -> List[Filterable]:
class BaseCommand(ABC):
+ #pylint: disable=too-many-arguments
def run(
self,
diagram: bool,
verbose: bool,
services: List[str],
filters: List[Filterable],
+ import_module: str,
):
raise NotImplementedError()
diff --git a/cloudiscovery/shared/diagram.py b/cloudiscovery/shared/diagram.py
index fb21a44..b5a5300 100644
--- a/cloudiscovery/shared/diagram.py
+++ b/cloudiscovery/shared/diagram.py
@@ -22,7 +22,9 @@
class Mapsources:
# diagrams modules that store classes that represent diagram elements
- diagrams_modules = [
+ provider = ""
+ modules_dict = {}
+ modules_dict["aws"] = [
"analytics",
"ar",
"blockchain",
@@ -51,6 +53,23 @@ class Mapsources:
"storage",
]
+ modules_dict['ibm'] = [
+ "analytics",
+ "applications",
+ "blockchain",
+ "compute",
+ "data",
+ "devops",
+ "general",
+ "infrastructure",
+ "management",
+ "network",
+ "security",
+ "social",
+ "storage",
+ "user",
+ ]
+
# Class to mapping type resource from Terraform to Diagram Nodes
mapresources = {
"aws_lambda_function": "Lambda",
@@ -228,9 +247,14 @@ class Mapsources:
"aws_vpn_connection": "SiteToSiteVpn",
"aws_vpn_gateway": "SiteToSiteVpn",
"aws_vpn_client_endpoint": "ClientVpn",
+ "ibm_vpc": "Vpc",
+ "ibm_security_group": "Firewall",
+ "ibm_network_acl": "Rules",
+ "ibm_subnet": "Subnet",
+ "ibm_route_table": "Router",
}
- resource_styles = build_styles()
+ resource_styles = build_styles(provider)
def add_resource_to_group(ordered_resources, group, resource):
@@ -307,19 +331,19 @@ def generate_diagram(
graph_attr={"nodesep": "2.0", "ranksep": "1.0", "splines": "curved"},
) as d:
d.dot.engine = self.engine
-
self.draw_diagram(ordered_resources=ordered_resources, relations=relations)
message_handler("\n\nPNG diagram generated", "HEADER")
message_handler("Check your diagram: " + output_filename + ".png", "OKBLUE")
+ # pylint: disable=exec-used
def draw_diagram(self, ordered_resources, relations):
already_drawn_elements = {}
-
- # Import all AWS nodes
- for module in Mapsources.diagrams_modules:
- exec("from diagrams.aws." + module + " import *")
-
+ # Import all AWS, IBM nodes
+ for key, val in Mapsources.modules_dict:
+ for module in val:
+ # pylint: disable=exec-used
+ exec("from diagrams." + key + "." + module + " import *")
nodes: Dict[ResourceDigest, any] = {}
# Iterate resources to draw it
for group_name in ordered_resources:
@@ -432,15 +456,22 @@ def build_diagram(
):
mx_graph_model = DIAGRAM_HEADER
cell_id = 1
-
+ isAWS = True
vpc_resource = None
for _, resource_group in resources.items():
for resource in resource_group:
- if resource.digest.type == "aws_vpc":
+ if resource.digest.type == "aws_vpc" or resource.digest.type == "ibm_vpc":
+ Mapsources.provider = "aws"
+ Mapsources.resource_styles = build_styles("aws")
if vpc_resource is None:
vpc_resource = resource
else:
raise Exception("Only one VPC in a region is supported now")
+ if resource.digest.type == "ibm_vpc":
+ isAWS = False
+ Mapsources.provider = "ibm"
+ Mapsources.resource_styles = build_styles("ibm")
+
if vpc_resource is None:
raise Exception("Only one VPC in a region is supported now")
@@ -448,7 +479,8 @@ def build_diagram(
vpc_box_height = 56565656
subnet_box_height = 424242
- vpc_cell = (
+ if isAWS:
+ vpc_cell = (
''
"".format(cell_id, vpc_resource.name, vpc_box_height)
)
+ else:
+ vpc_cell = (
+ ''
+ "".format(cell_id, vpc_resource.name, vpc_box_height)
+ )
cell_id += 1
mx_graph_model += vpc_cell
@@ -479,7 +520,8 @@ def build_diagram(
public_subnet_y = 40
cell_id += 1
# pylint: disable=line-too-long
- public_subnet = (
+ if isAWS:
+ public_subnet = (
''.format_map(
+ {
+ "X": str(public_subnet_x),
+ "Y": str(public_subnet_y),
+ "H": subnet_box_height,
+ "W": subnet_box_width,
+ }
+ )
+ )
mx_graph_model += public_subnet
(mx_graph_model, public_rows) = self.render_subnet_items(
@@ -512,7 +570,8 @@ def build_diagram(
private_subnet_x = 480
private_subnet_y = 40
cell_id += 1
- private_subnet = (
+ if isAWS:
+ private_subnet = (
''.format_map(
+ {
+ "X": str(private_subnet_x),
+ "Y": str(private_subnet_y),
+ "H": 200,
+ "W": 200,
+ }
+ )
+ )
mx_graph_model += private_subnet
(mx_graph_model, private_rows) = self.render_subnet_items(
@@ -552,15 +627,22 @@ def build_diagram(
public_subnet_x = 0
for _, resource_group in resources.items():
for resource in resource_group:
- if resource.digest.type in ["aws_subnet", "aws_vpc"]:
+ if resource.digest.type in ["aws_subnet", "aws_vpc", "ibm_subnet", "ibm_vpc"]:
continue
if resource.digest not in added_resources:
added_resources.append(resource.digest)
- style = (
+ if isAWS:
+ style = (
Mapsources.resource_styles[resource.digest.type]
if resource.digest.type in Mapsources.resource_styles
else Mapsources.resource_styles["aws_general"]
- )
+ )
+ else:
+ style = (
+ Mapsources.resource_styles[resource.digest.type]
+ if resource.digest.type in Mapsources.resource_styles
+ else Mapsources.resource_styles["ibm_general"]
+ )
cell = CELL_TEMPLATE.format_map(
{
"CELL_IDX": resource.digest.to_string(),
@@ -605,7 +687,7 @@ def render_subnet_items(
row = 0
# pylint: disable=too-many-nested-blocks
for relation in resource_relations:
- if relation.to_node == ResourceDigest(id=subnet_id, type="aws_subnet"):
+ if relation.to_node == ResourceDigest(id=subnet_id, type=("aws_subnet" or "ibm_subnet")):
for _, resource_group in resources.items():
for resource in resource_group:
if (
@@ -640,4 +722,6 @@ def has_subnet_type(subnet_id, resource_relations) -> bool:
for relation in resource_relations:
if relation.to_node == ResourceDigest(id=subnet_id, type="aws_subnet"):
return True
+ if relation.to_node == ResourceDigest(id=subnet_id, type="ibm_subnet"):
+ return True
return False
diff --git a/cloudiscovery/shared/diagramsnet.py b/cloudiscovery/shared/diagramsnet.py
index ce1ba94..c01b115 100644
--- a/cloudiscovery/shared/diagramsnet.py
+++ b/cloudiscovery/shared/diagramsnet.py
@@ -32,227 +32,273 @@
w2 = s * 78
-def _add_general_resources(styles):
- n3 = (
+def _add_general_resources(styles, provider):
+ if provider == "aws":
+ n3 = (
"gradientDirection=north;outlineConnect=0;fontColor=#232F3E;gradientColor=#505863;fillColor=#1E262E;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
-
- styles["aws_general"] = n3 + "resourceIcon;resIcon=" + gn + ".general;"
-
+ )
+ elif provider == "ibm":
+ n3 = (
+ "gradientDirection=north;outlineConnect=0;fontColor=#232F3E;gradientColor=#505863;fillColor=#1E262E;"
+ "strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
+ "fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.ibm."
+ )
+ styles["ibm_general"] = n3 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".general;"
-def _add_analytics_resources(styles):
- n2 = (
+def _add_analytics_resources(styles, provider):
+ if provider == "aws":
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#945DF2;gradientDirection=north;fillColor=#5A30B5;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
- styles["aws_athena"] = n2 + "resourceIcon;resIcon=" + gn + ".athena;"
- styles["aws_elasticsearch_domain"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".elasticsearch_service;"
- )
- styles["aws_emr"] = n2 + "resourceIcon;resIcon=" + gn + ".emr;"
- styles["aws_emr_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".emr;"
- styles["aws_kinesis"] = n2 + "resourceIcon;resIcon=" + gn + ".kinesis;"
- styles["aws_kinesisanalytics"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".kinesis_data_analytics;"
- )
- styles["aws_kinesis_firehose"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".kinesis_data_firehose;"
- )
- styles["aws_quicksight"] = n2 + "resourceIcon;resIcon=" + gn + ".quicksight;"
- styles["aws_redshift"] = n2 + "resourceIcon;resIcon=" + gn + ".redshift;"
- styles["aws_data_pipeline"] = n2 + "resourceIcon;resIcon=" + gn + ".data_pipeline;"
- styles["aws_msk_cluster"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".managed_streaming_for_kafka;"
- )
- styles["aws_glue"] = n2 + "resourceIcon;resIcon=" + gn + ".glue;"
- styles["aws_lakeformation"] = n2 + "resourceIcon;resIcon=" + gn + ".lake_formation;"
-
-
-def _add_application_integration_resources(styles):
- n2 = (
+ )
+ styles["aws_athena"] = n2 + "resourceIcon;resIcon=" + gn + ".athena;"
+ styles["aws_elasticsearch_domain"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".elasticsearch_service;"
+ )
+ styles["aws_emr"] = n2 + "resourceIcon;resIcon=" + gn + ".emr;"
+ styles["aws_emr_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".emr;"
+ styles["aws_kinesis"] = n2 + "resourceIcon;resIcon=" + gn + ".kinesis;"
+ styles["aws_kinesisanalytics"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".kinesis_data_analytics;"
+ )
+ styles["aws_kinesis_firehose"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".kinesis_data_firehose;"
+ )
+ styles["aws_quicksight"] = n2 + "resourceIcon;resIcon=" + gn + ".quicksight;"
+ styles["aws_redshift"] = n2 + "resourceIcon;resIcon=" + gn + ".redshift;"
+ styles["aws_data_pipeline"] = n2 + "resourceIcon;resIcon=" + gn + ".data_pipeline;"
+ styles["aws_msk_cluster"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".managed_streaming_for_kafka;"
+ )
+ styles["aws_glue"] = n2 + "resourceIcon;resIcon=" + gn + ".glue;"
+ styles["aws_lakeformation"] = n2 + "resourceIcon;resIcon=" + gn + ".lake_formation;"
+ else:
+ n2 = (
+ "outlineConnect=0;fontColor=#232F3E;gradientColor=#945DF2;gradientDirection=north;fillColor=#5A30B5;"
+ "strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
+ "fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.ibm."
+ )
+ styles["aws_athena"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".athena;"
+ styles["aws_elasticsearch_domain"] = (
+ n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".elasticsearch_service;"
+ )
+ styles["aws_emr"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".emr;"
+ styles["aws_emr_cluster"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".emr;"
+ styles["aws_kinesis"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".kinesis;"
+ styles["aws_kinesisanalytics"] = (
+ n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".kinesis_data_analytics;"
+ )
+ styles["aws_kinesis_firehose"] = (
+ n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".kinesis_data_firehose;"
+ )
+ styles["aws_quicksight"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".quicksight;"
+ styles["aws_redshift"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".redshift;"
+ styles["aws_data_pipeline"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".data_pipeline;"
+ styles["aws_msk_cluster"] = (
+ n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".managed_streaming_for_kafka;"
+ )
+ styles["aws_glue"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".glue;"
+ styles["aws_lakeformation"] = n2 + "resourceIcon;resIcon=" + "mxgraph.ibm" + ".lake_formation;"
+
+def _add_application_integration_resources(styles, provider):
+ if provider == "aws":
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#F34482;gradientDirection=north;fillColor=#BC1356;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
-
- styles["aws_sns_topic"] = n2 + "resourceIcon;resIcon=" + gn + ".sns;"
- styles["aws_sqs"] = n2 + "resourceIcon;resIcon=" + gn + ".sqs;"
- styles["aws_appsync_graphql_api"] = n2 + "resourceIcon;resIcon=" + gn + ".appsync;"
- styles["aws_events"] = n2 + "resourceIcon;resIcon=" + gn + ".eventbridge;"
-
-
-def _add_compute_resources(styles):
- n = (
+ )
+ styles["aws_sns_topic"] = n2 + "resourceIcon;resIcon=" + gn + ".sns;"
+ styles["aws_sqs"] = n2 + "resourceIcon;resIcon=" + gn + ".sqs;"
+ styles["aws_appsync_graphql_api"] = n2 + "resourceIcon;resIcon=" + gn + ".appsync;"
+ styles["aws_events"] = n2 + "resourceIcon;resIcon=" + gn + ".eventbridge;"
+
+def _add_compute_resources(styles, provider):
+ if provider == "aws":
+ n = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#D05C17;strokeColor=none;dashed=0;"
"verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;"
"pointerEvents=1;shape=mxgraph.aws4."
- )
- n2 = (
+ )
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
+ )
- styles["aws_instance"] = n2 + "resourceIcon;resIcon=" + gn + ".ec2;"
- styles["aws_autoscaling_group"] = (
+ styles["aws_instance"] = n2 + "resourceIcon;resIcon=" + gn + ".ec2;"
+ styles["aws_autoscaling_group"] = (
n2 + "resourceIcon;resIcon=" + gn + ".auto_scaling2;"
- )
- styles["aws_batch"] = n2 + "resourceIcon;resIcon=" + gn + ".batch;"
- styles["aws_elastic_beanstalk_environment"] = (
+ )
+ styles["aws_batch"] = n2 + "resourceIcon;resIcon=" + gn + ".batch;"
+ styles["aws_elastic_beanstalk_environment"] = (
n2 + "resourceIcon;resIcon=" + gn + ".elastic_beanstalk;"
- )
- styles["aws_lambda_function"] = n + "lambda_function;"
-
+ )
+ styles["aws_lambda_function"] = n + "lambda_function;"
-def _add_container_resources(styles):
- n2 = (
+def _add_container_resources(styles, provider):
+ if provider == "aws":
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
+ )
+ styles["aws_eks_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".eks;"
+ styles["aws_ecr"] = n2 + "resourceIcon;resIcon=" + gn + ".ecr;"
+ styles["aws_ecs_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".ecs;"
- styles["aws_eks_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".eks;"
- styles["aws_ecr"] = n2 + "resourceIcon;resIcon=" + gn + ".ecr;"
- styles["aws_ecs_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".ecs;"
-
-def _add_customer_engagement_resources(styles):
- n2 = (
+def _add_customer_engagement_resources(styles, provider):
+ if provider == "aws":
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#4D72F3;gradientDirection=north;fillColor=#3334B9;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
-
- styles["aws_connect"] = n2 + "resourceIcon;resIcon=" + gn + ".connect;"
- styles["aws_pinpoint"] = n2 + "resourceIcon;resIcon=" + gn + ".pinpoint;"
- styles["aws_ses"] = n2 + "resourceIcon;resIcon=" + gn + ".simple_email_service;"
+ )
+ styles["aws_connect"] = n2 + "resourceIcon;resIcon=" + gn + ".connect;"
+ styles["aws_pinpoint"] = n2 + "resourceIcon;resIcon=" + gn + ".pinpoint;"
+ styles["aws_ses"] = n2 + "resourceIcon;resIcon=" + gn + ".simple_email_service;"
-def _add_database_resources(styles):
- n = (
+def _add_database_resources(styles, provider):
+ if provider == "aws":
+ n = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#3334B9;strokeColor=none;dashed=0;"
"verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;"
"pointerEvents=1;shape=mxgraph.aws4."
- )
- n2 = (
+ )
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#4D72F3;gradientDirection=north;fillColor=#3334B9;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
-
- styles["aws_docdb_cluster"] = (
+ )
+ styles["aws_docdb_cluster"] = (
n2 + "resourceIcon;resIcon=" + gn + ".documentdb_with_mongodb_compatibility;"
- )
- styles["aws_dynamodb"] = n2 + "resourceIcon;resIcon=" + gn + ".dynamodb;"
- styles["aws_elasticache_cluster"] = (
+ )
+ styles["aws_dynamodb"] = n2 + "resourceIcon;resIcon=" + gn + ".dynamodb;"
+ styles["aws_elasticache_cluster"] = (
n2 + "resourceIcon;resIcon=" + gn + ".elasticache;"
- )
- styles["aws_neptune_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".neptune;"
- styles["aws_redshift"] = n2 + "resourceIcon;resIcon=" + gn + ".redshift;"
+ )
+ styles["aws_neptune_cluster"] = n2 + "resourceIcon;resIcon=" + gn + ".neptune;"
+ styles["aws_redshift"] = n2 + "resourceIcon;resIcon=" + gn + ".redshift;"
- styles["aws_db_instance"] = n + "rds_instance;"
- styles["aws_dax"] = n + "dynamodb_dax;"
+ styles["aws_db_instance"] = n + "rds_instance;"
+ styles["aws_dax"] = n + "dynamodb_dax;"
-def _add_ml_resources(styles):
- n2 = (
+def _add_ml_resources(styles, provider):
+ if provider == "aws":
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#4AB29A;gradientDirection=north;fillColor=#116D5B;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
+ )
+ styles["aws_sagemaker"] = n2 + "resourceIcon;resIcon=" + gn + ".sagemaker;"
- styles["aws_sagemaker"] = n2 + "resourceIcon;resIcon=" + gn + ".sagemaker;"
-
-
-def _add_management_governance_resources(styles):
- n2 = (
+def _add_management_governance_resources(styles, provider):
+ if provider == "aws":
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#F34482;gradientDirection=north;fillColor=#BC1356;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
-
- styles["aws_cloudwatch"] = n2 + "resourceIcon;resIcon=" + gn + ".cloudwatch_2;"
- styles["aws_autoscaling_group"] = (
+ )
+ styles["aws_cloudwatch"] = n2 + "resourceIcon;resIcon=" + gn + ".cloudwatch_2;"
+ styles["aws_autoscaling_group"] = (
n2 + "resourceIcon;resIcon=" + gn + ".autoscaling;"
- )
- styles["aws_auto_scaling"] = n2 + "resourceIcon;resIcon=" + gn + ".autoscaling;"
- styles["aws_cloudformation"] = (
+ )
+ styles["aws_auto_scaling"] = n2 + "resourceIcon;resIcon=" + gn + ".autoscaling;"
+ styles["aws_cloudformation"] = (
n2 + "resourceIcon;resIcon=" + gn + ".cloudformation;"
- )
-
-
-def _add_network_resources(styles):
- n = (
- "outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#5A30B5;strokeColor=none;dashed=0;"
- "verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;"
- "pointerEvents=1;shape=mxgraph.aws4."
- )
- n2 = (
- "outlineConnect=0;fontColor=#232F3E;gradientColor=#945DF2;gradientDirection=north;fillColor=#5A30B5;"
- "strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
- "fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
-
- styles["aws_api_gateway_rest_api"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".api_gateway;"
- )
- styles["aws_cloudfront_distribution"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".cloudfront;"
- )
- styles["aws_vpc"] = n2 + "resourceIcon;resIcon=" + gn + ".vpc;"
- styles["aws_vpn_client_endpoint"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".client_vpn;"
- )
- styles["aws_elb"] = n2 + "resourceIcon;resIcon=" + gn + ".elastic_load_balancing;"
- styles["aws_directconnect"] = n2 + "resourceIcon;resIcon=" + gn + ".direct_connect;"
- styles["aws_global_accelerator"] = (
- n2 + "resourceIcon;resIcon=" + gn + ".global_accelerator;"
- )
-
- styles["aws_route_table"] = n + "route_table;"
- styles["aws_vpc_endpoint_gateway"] = n + "gateway;"
- styles["aws_internet_gateway"] = n + "internet_gateway;"
- styles["aws_nat_gateway"] = n + "nat_gateway;"
- styles["aws_network_acl"] = n + "network_access_control_list;"
- styles["aws_elb_classic"] = n + "classic_load_balancer;"
- styles["aws_vpn_connection"] = n + "vpn_connection;"
- styles["aws_vpn_gateway"] = n + "vpn_gateway;"
-
-
-def _add_storage_resources(styles):
- n = (
+ )
+
+def _add_network_resources(styles, provider):
+ if provider == "aws":
+ n = (
+ "outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#5A30B5;strokeColor=none;dashed=0;"
+ "verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;"
+ "pointerEvents=1;shape=mxgraph.aws4."
+ )
+ n2 = (
+ "outlineConnect=0;fontColor=#232F3E;gradientColor=#945DF2;gradientDirection=north;fillColor=#5A30B5;"
+ "strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
+ "fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
+ )
+ styles["aws_api_gateway_rest_api"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".api_gateway;"
+ )
+ styles["aws_cloudfront_distribution"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".cloudfront;"
+ )
+ styles["aws_vpc"] = n2 + "resourceIcon;resIcon=" + gn + ".vpc;"
+ styles["aws_vpn_client_endpoint"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".client_vpn;"
+ )
+ styles["aws_elb"] = n2 + "resourceIcon;resIcon=" + gn + ".elastic_load_balancing;"
+ styles["aws_directconnect"] = n2 + "resourceIcon;resIcon=" + gn + ".direct_connect;"
+ styles["aws_global_accelerator"] = (
+ n2 + "resourceIcon;resIcon=" + gn + ".global_accelerator;"
+ )
+ styles["aws_route_table"] = n + "route_table;"
+ styles["aws_vpc_endpoint_gateway"] = n + "gateway;"
+ styles["aws_internet_gateway"] = n + "internet_gateway;"
+ styles["aws_nat_gateway"] = n + "nat_gateway;"
+ styles["aws_network_acl"] = n + "network_access_control_list;"
+ styles["aws_elb_classic"] = n + "classic_load_balancer;"
+ styles["aws_vpn_connection"] = n + "vpn_connection;"
+ styles["aws_vpn_gateway"] = n + "vpn_gateway;"
+ else:
+ styles["ibm_route_table"] = (
+ "outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#5A30B5;strokeColor=none;dashed=0;"
+ "verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;"
+ "pointerEvents=1;shape=mxgraph.aws4.route_table;"
+ )
+ styles["ibm_security_group"] = 'fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;'
+ styles["ibm_security_group"] = styles["ibm_security_group"] + 'rounded=0;whiteSpace=wrap;html=1;'
+ styles["ibm_security_group"] = styles["ibm_security_group"] + 'strokeColor=#FF0000;strokeWidth=2;'
+ styles["ibm_security_group"] = styles["ibm_security_group"] + 'dashed=1;container=1;collapsible=0;'
+ styles["ibm_security_group"] = styles["ibm_security_group"] + 'expand=0;recursiveResize=0;'
+ styles["ibm_network_acl"] = 'shape=mxgraph.ibm.box;prType=subnet;fontStyle=0;verticalAlign=top;'
+ styles["ibm_network_acl"] = styles["ibm_network_acl"] + 'align=left;spacingLeft=32;spacingTop=4;'
+ styles["ibm_network_acl"] = styles["ibm_network_acl"] + 'fillColor=#E6F0E2;rounded=0;whiteSpace=wrap;'
+ styles["ibm_network_acl"] = styles["ibm_network_acl"] + 'html=1;strokeColor=#00882B;strokeWidth=1;dashed=0;'
+ styles["ibm_network_acl"] = styles["ibm_network_acl"] + 'container=1;spacing=-4;collapsible=0;expand=0;'
+ styles["ibm_network_acl"] = styles["ibm_network_acl"] + 'recursiveResize=0;'
+
+
+def _add_storage_resources(styles, provider):
+ if provider == "aws":
+ n = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#277116;strokeColor=none;dashed=0;"
"verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;"
"pointerEvents=1;shape=mxgraph.aws4."
- )
- n2 = (
+ )
+ n2 = (
"outlineConnect=0;fontColor=#232F3E;gradientColor=#60A337;gradientDirection=north;fillColor=#277116;"
"strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;"
"fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4."
- )
+ )
- styles["aws_efs_file_system"] = (
+ styles["aws_efs_file_system"] = (
n2 + "resourceIcon;resIcon=" + gn + ".elastic_file_system;"
- )
- styles["aws_fsx"] = n2 + "resourceIcon;resIcon=" + gn + ".fsx;"
+ )
+ styles["aws_fsx"] = n2 + "resourceIcon;resIcon=" + gn + ".fsx;"
- styles["aws_s3"] = n + "bucket;"
+ styles["aws_s3"] = n + "bucket;"
-def build_styles():
+def build_styles(provider):
styles = {}
- _add_general_resources(styles)
- _add_analytics_resources(styles)
- _add_application_integration_resources(styles)
- _add_compute_resources(styles)
- _add_container_resources(styles)
- _add_customer_engagement_resources(styles)
- _add_database_resources(styles)
- _add_ml_resources(styles)
- _add_management_governance_resources(styles)
- _add_network_resources(styles)
- _add_storage_resources(styles)
+ _add_general_resources(styles, provider)
+ _add_analytics_resources(styles, provider)
+ _add_application_integration_resources(styles, provider)
+ _add_compute_resources(styles, provider)
+ _add_container_resources(styles, provider)
+ _add_customer_engagement_resources(styles, provider)
+ _add_database_resources(styles, provider)
+ _add_ml_resources(styles, provider)
+ _add_management_governance_resources(styles, provider)
+ _add_network_resources(styles, provider)
+ _add_storage_resources(styles, provider)
return styles
diff --git a/cloudiscovery/shared/parameters.py b/cloudiscovery/shared/parameters.py
index d05ec10..7284f98 100644
--- a/cloudiscovery/shared/parameters.py
+++ b/cloudiscovery/shared/parameters.py
@@ -18,6 +18,27 @@ def generate_parser():
subparsers = parser.add_subparsers(help="commands", dest="command")
+ vpc_parser = subparsers.add_parser("ibm-vpc", help="Analyze VPCs")
+ add_default_arguments(vpc_parser)
+ vpc_parser.add_argument(
+ "-v",
+ "--vpc_id",
+ required=False,
+ help="Inform VPC to analyze. If not informed, script will check all vpcs.",
+ )
+ vpc_parser.add_argument(
+ "-n",
+ "--region_name",
+ required=False,
+ help="Inform region name to analyze.",
+ )
+ vpc_parser.add_argument(
+ "-a",
+ "--api_key",
+ required=False,
+ help="Inform apikey to login to cloud.",
+ )
+
vpc_parser = subparsers.add_parser("aws-vpc", help="Analyze VPCs")
add_default_arguments(vpc_parser)
vpc_parser.add_argument(