import traceback
from typing import Any
import demistomock as demisto # noqa: F401
from CommonServerPython import * # noqa: F401
""" STANDALONE FUNCTION """
def lookup(parent_obj: str, level: int) -> tuple[str, dict]:
"""
Lookup information on a folder or organization object. Unless the current lookup
is a organization object, it returns parent object to lookup and results of current lookup.
Args:
parent_obj (str): organization/folder object in number format.
level (int): the current level that the object is (ascending).
Returns:
str: parent object to look up next or "NONE" for error handling and "stop" if no parent.
dict: dictionary of id, name and level of the lookup object.
"""
temp: dict[str, str] = {}
try:
if "folder" in parent_obj:
folder_info = execute_command("gcp-iam-folders-get", {"folder_name": parent_obj})
if not folder_info:
return "NONE", temp
name = "folders/" + folder_info.get("displayName", "")
temp["level"] = str(level)
temp["id"] = name
temp["number"] = folder_info.get("name", "")
next_one = folder_info.get("parent", "")
elif "organization" in parent_obj:
next_one = "stop"
temp["level"] = str(level)
temp["id"] = parent_obj
temp["number"] = parent_obj
else:
raise ValueError("unexpected object type")
except TypeError:
return "NONE", temp
else:
return next_one, temp
""" COMMAND FUNCTION """
def gcp_project_heirarchy(args: dict[str, Any]) -> CommandResults:
"""
Determine GCP project hierarchy by looking up parent objects until the organization level is reached.
Args:
args (dict): Command arguments from XSOAR.
Returns:
list[CommandResults]: outputs, readable outputs and raw response for XSOAR.
"""
project_id = args.get("project_id")
if not project_id:
raise ValueError("project_id not specified")
full_project = "projects/" + project_id
project_info = execute_command("gcp-iam-projects-get", {"project_name": full_project})
if not project_info:
return CommandResults("could not find specified project info")
level = 1
hierarchy = [{"level": "project", "id": full_project, "number": project_info.get("name", "")}]
next_one, to_append = lookup(project_info.get("parent", ""), level)
if next_one == "NONE":
return CommandResults("could not find specified folder/organization info")
hierarchy.append(to_append)
try:
while "stop" not in next_one:
level += 1
next_one, to_append = lookup(next_one, level)
if next_one == "NONE" or next_one is None:
return CommandResults("could not find specified folder/organization info")
hierarchy.append(to_append)
except TypeError:
return CommandResults("could not find specified folder/organization info")
return CommandResults(
outputs_prefix="GCPHierarchy",
outputs_key_field="level",
outputs=hierarchy,
)
""" MAIN FUNCTION """
def main():
try:
return_results(gcp_project_heirarchy(demisto.args()))
except Exception as ex:
demisto.error(traceback.format_exc()) # print the traceback
return_error(f"Failed to execute GCPProjectHierarchy. Error: {ex!s}")
""" ENTRY POINT """
if __name__ in ("__main__", "__builtin__", "builtins"):
main()
README
Determine GCP project hierarchy by looking up parent objects until the organization level is reached.
Script Data
Name
Description
Script Type
python3
Cortex XSOAR Version
6.8.0
Inputs
Argument Name
Description
project_id
The project ID instead of the project number. No need to supply projects/ before the ID (i.e., use `project-name` instead of `projects/project-name` or `projects/111111111111`).
Outputs
Path
Description
Type
GCPHierarchy.id
ID of the project/folder/organization object, such as `folders/folder-name`.
string
GCPHierarchy.level
Level in relation to the original project such as project, 1, 2, etc.
string
GCPHierarchy.number
Number of the project/folder/organization object such as `folders/111111111111`.