Google Resource Manager
Google Cloud Platform Resource Manager.
IT Services · Google Resource Manager
Details
| ID | Google Resource Manager |
|---|---|
| Provider | |
| Category | IT Services |
| From Version | 5.0.0 |
| Docker Image | demisto/googleapi-python3:1.0.0.115338 |
| Supported Modules | Agentix XSIAM |
README
Configure Google Resource Manager on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for Google Resource Manager.
- Click Add instance to create and configure a new integration instance.
- Name: a textual name for the integration instance.
- Project ID
- Private Key ID
- Private Key
- Client Email
- Client ID
- Client X509 Cert URL
- Use system proxy settings
- Click Test to validate the URLs, token, and connection.
Commands
You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
- Create a new project: grm-create-project
- Get information for a project: grm-get-project
- Get a list of all projects: grm-list-projects
- Update a project: grm-update-project
- Search organization resources: grm-search-organizations
- Get information for an organization: grm-get-organization
- Delete a project: grm-delete-project
- Restore a project: grm-undelete-project
1. Create a new project
Creates a new Project resource with the user-specified values passed as command arguments.
Base Command
grm-create-project
Input
| Argument Name | Description | Required |
|---|---|---|
| project_id | The unique, user-assigned ID of the Project. It must be 6 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited. Example: tokyo-rain-123 | Required |
| parent_id | The ID of the parent resource. Organizations' Name output is in the format "organizations/12345" where the numbers after the forward slash are the ID of the organization. To find Organization IDs available to assign as a parent resource try running the grm-search-organization command. | Required |
| label_keys | The label keys associated with this Project. Label keys must be between 1 and 63 characters long and conform to the following regular expression: [a-z]([-a-z0-9]*[a-z0-9])?. You can associate a maximum of 256 labels with a given resource. |
Optional |
| name | The user-assigned display name of the Project. It must be 4 to 30 characters. Supported characters: lowercase and uppercase letters, numbers, hyphens, single-quotes, double-quotes, spaces, and exclamation points. Example: My Project | Optional |
| parent_type | Represents the resource type the parent_id is for. Valid resource types: "organization" and "folder". | Required |
| label_values | The label values associated with this Project. Label values must be between 0 and 63 characters long and conform to the following regular expression [a-z]([-a-z0-9]*[a-z0-9])?. A label value can be empty. You can associate a maximum of 256 labels with a given resource. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Project.Name | String | The user-assigned display name of the Project |
| GRM.Project.ID | String | The unique, user-assigned ID of the Project |
| GRM.Project.Number | String | The number uniquely identifying the Project |
| GRM.Project.State | String | The Project lifecycle state |
| GRM.Project.CreateTime | Date | createTime - The time the resource was created |
| GRM.Project.Label | Unknown | The labels associated with this Project |
| GRM.Project.Parent.ID | String | ID of the parent resource |
| GRM.Project.Parent.Type | String | Type of the parent resource |
Command Example
grm-create-project project_id=faramir-111 parent_id=690006273490 parent_type=organization name="Faramir"
Context Example
{
"GRM.Project": {
"Name": "Faramir",
"Parent": {
"Type": "organization",
"ID": "690006273490"
},
"Number": "110336878499",
"Label": null,
"State": "ACTIVE",
"ID": "faramir-111",
"CreateTime": "2019-01-15T12:30:21.267Z"
}
}
Human Readable Output
Google Cloud Project Successfully Created
| Name | Parent | Number | ID | State | Label | CreateTime |
|---|---|---|---|---|---|---|
| Faramir | Type: organization ID: 690006273490 |
110336878499 | faramir-111 | ACTIVE | 2019-01-15T12:30:21.267Z |
2. Getting information for a project
Retrieves the Project by the specified project_id, e.g., my-project-123.
Base Command
grm-get-project
Input
| Argument Name | Description | Required |
|---|---|---|
| project_id | The unique ID of the Project to fetch, e.g., tokyo-rain-123. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Project.Number | String | The number uniquely identifying the Project |
| GRM.Project.ID | String | The unique, user-assigned ID of the Project |
| GRM.Project.State | String | The Project lifecycle state |
| GRM.Project.Name | String | The user-assigned display name of the Project |
| GRM.Project.CreateTime | Date | createTime - The time the resource was created |
| GRM.Project.Label | Unknown | The labels associated with this Project |
| GRM.Project.Parent.ID | String | ID of the parent resource |
| GRM.Project.Parent.Type | String | Type of the parent resource |
Command Example
grm-get-project project_id=faramir-111
Context Example
{
"GRM.Project": {
"Name": "Faramir",
"Parent": {
"Type": "organization",
"ID": "690006273490"
},
"Number": "110336878499",
"Label": null,
"State": "ACTIVE",
"ID": "faramir-111",
"CreateTime": "2019-01-15T12:30:21.267Z"
}
}
Human Readable Output
Details of Fetched Google Cloud Project
| Name | Parent | Number | ID | State | Label | CreateTime |
|---|---|---|---|---|---|---|
| Faramir | Type: organization ID: 690006273490 |
110336878499 | faramir-111 | ACTIVE | 2019-01-15T12:30:21.267Z |
3. Get a list of all projects
Lists projects that are visible to the user and satisfies the specified filter. Projects are returned in an unspecified order.
Base Command
grm-list-projects
Input
| Argument Name | Description | Required |
|---|---|---|
| filter | An expression for filtering the results of the request. Filter rules are case insensitive. The fields eligible for filtering are:
Examples:
|
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Project.Name | String | The user-assigned display name of the Project |
| GRM.Project.ID | String | The unique, user-assigned ID of the Project |
| GRM.Project.Number | String | The number uniquely identifying the Project |
| GRM.Project.State | String | The Project lifecycle state. |
| GRM.Project.CreateTime | Date | The time the resource was created |
| GRM.Project.Label | Unknown | The labels associated with this Project |
| GRM.Project.Parent.ID | String | ID of the parent resource |
| GRM.Project.Parent.Type | String | Type of the parent resource |
Command Example
grm-list-projects filter="id:faramir*"
Context Example
{
"GRM.Project": [
{
"Name": "Faramir 2",
"Parent": {
"Type": "organization",
"ID": "690006273490"
},
"Number": "877118493152",
"Label": null,
"State": "ACTIVE",
"ID": "faramir-222",
"CreateTime": "2019-01-20T07:42:58.155Z"
},
{
"Name": "Faramir",
"Parent": {
"Type": "organization",
"ID": "690006273490"
},
"Number": "110336878499",
"Label": null,
"State": "ACTIVE",
"ID": "faramir-111",
"CreateTime": "2019-01-15T12:30:21.267Z"
}
]
}
Human Readable Output
Projects Filtered by 'id:faramir*'
| Name | Parent | Number | ID | State | Label | CreateTime |
|---|---|---|---|---|---|---|
| Faramir 2 | Type: organization ID: 690006273490 |
877118493152 | faramir-222 | ACTIVE | 2019-01-20T07:42:58.155Z | |
| Faramir | Type: organization ID: 690006273490 |
110336878499 | faramir-111 | ACTIVE | 2019-01-15T12:30:21.267Z |
4. Update a project
Updates the attributes of the Project identified by the specified project_id. Currently the only fields that can be updated are the project name and labels.
Base Command
grm-update-project
Input
| Argument Name | Description | Required |
|---|---|---|
| project_id | The unique ID of the Project to update. Example: tokyo-rain-123 |
Required |
| name | The string to update the Project name with. It must be 4 to 30 characters. Supported characters are: lowercase and uppercase letters, numbers, hyphens, single-quotes, double-quotes, spaces, and exclamation points. Example: My Project |
Optional |
| parent_id | The ID of the parent resource. Organizations' Name output is in the format organizations/12345 where the numbers after the forward slash are the ID of the organization. To find Organization IDs available to assign as a parent resource try running the grm-search-organization command. |
Required |
| parent_type | The resource type the parent_id is for. Valid resource types: "organization" and "folder". | Required |
| label_keys | The label keys to associate with this Project. Label keys must be between 1 and 63 characters long and conform to the following regular expression: [a-z]([-a-z0-9]*[a-z0-9])? You can associate a maximum of 256 labels with a given resource. |
Optional |
| label_values | The label values to associate with this Project. Label values must be between 0 and 63 characters long and conform to the following regular expression [a-z]([-a-z0-9]*[a-z0-9])?. A label value can be empty. You can associate a maximum of 256 labels with a given resource. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Project.Name | String | The user-assigned display name of the Project |
| GRM.Project.ID | String | The unique, user-assigned ID of the Project |
| GRM.Project.Number | String | The number uniquely identifying the Project |
| GRM.Project.State | String | The Project lifecycle state. |
| GRM.Project.CreateTime | Date | The time the resource was created |
| GRM.Project.Label | Unknown | The labels associated with this Project |
| GRM.Project.Parent.ID | String | ID of the parent resource |
| GRM.Project.Parent.Type | String | Type of the parent resource |
Command Example
grm-update-project project_id=faramir-111 parent_id=690006273490 parent_type=organization name="Faramir-Updated"
Context Example
{
"GRM.Project": {
"Name": "Faramir-Updated",
"Parent": {
"Type": "organization",
"ID": "690006273490"
},
"Number": "110336878499",
"Label": null,
"State": "ACTIVE",
"ID": "faramir-111",
"CreateTime": "2019-01-15T12:30:21.267Z"
}
}
Human Readable Output
Details of Updated Google Cloud Project
| Name | Parent | Number | ID | State | Label | CreateTime |
|---|---|---|---|---|---|---|
| Faramir-Updated | Type: organization ID: 690006273490 |
110336878499 | faramir-111 | ACTIVE | 2019-01-15T12:30:21.267Z |
5. Search organization resources
Searches Organization resources that are visible to the user and satisfies the specified filter. Organizations are returned in an unspecified order. New Organizations do not necessarily appear at the end of the results.
Base Command
grm-search-organizations
Input
| Argument Name | Description | Required |
|---|---|---|
| page_size | The maximum number of Organizations to return in the response. | Optional |
| page_token | A pagination token returned from a previous call to "organizations.search" that indicates from where the listing should continue | Optional |
| filter | An expression for filtering the Organizations returned in the results. Filter rules are case-insensitive. Organizations can be filtered by 'owner.directoryCustomerId' or by 'domain', where the domain is a G Suite domain, e.g., owner.directorycustomerid:123456789 Organizations with owner.directory_customer_id equal to 123456789. domain:google.com Organizations corresponding to the domain google.com. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Organization.Name | String | The resource name of the organization. This is the organization's relative path in the API. Its format is "organizations/[organization_id]" e.g. "organizations/1234". |
| GRM.Organization.State | String | The organization's current lifecycle state |
| GRM.Organization.CreateTime | Date | The time the organization resource was created |
| GRM.Organization.Owner.CustomerID | String | The G Suite customer ID used in the Directory API |
Command Example
grm-search-organizations
Context Example
{
"GRM.Organization": [
{
"Owner": {
"CustomerID": "C02f0zfqw"
},
"State": "ACTIVE",
"CreateTime": "2017-04-25T13:41:05.196Z",
"Name": "organizations/690006273490"
}
]
}
Human Readable Output
Organizations
| Owner | State | Name | CreateTime |
|---|---|---|---|
| CustomerID: C02f0zfqw | ACTIVE | organizations/690006273490 | 2017-04-25T13:41:05.196Z |
6. Get information for an organization
Returns an Organization resource identified by the specified resource name.
Base Command
grm-get-organization
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The resource name of the Organization to fetch, e.g., "organizations/1234". | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Organization.Name | String | The resource name of the organization. This is the organization's relative path in the API. Its format is "organizations/[organization_id]" e.g., "organizations/1234" |
| GRM.Organization.State | String | The organization's current lifecycle state |
| GRM.Organization.CreateTime | Date | The time the organization resource was created |
| GRM.Organization.Owner.CustomerID | String | The G Suite customer ID used in the Directory API |
Command Example
grm-get-organization name=organizations/690006273490
Context Example
{
"GRM.Organization": {
"Owner": {
"CustomerID": "C02f0zfqw"
},
"State": "ACTIVE",
"CreateTime": "2017-04-25T13:41:05.196Z",
"Name": "organizations/690006273490"
}
}
Human Readable Output
Details of Fetched Organization
| Owner | State | Name | CreateTime |
|---|---|---|---|
| CustomerID: C02f0zfqw | ACTIVE | organizations/690006273490 | 2017-04-25T13:41:05.196Z |
7. Delete an organization
Marks the Project identified by the specified project_id to be deleted, e.g., my-project-123.
Base Command
grm-delete-project
Input
| Argument Name | Description | Required |
|---|---|---|
| project_id | The unique ID of the Project to delete. Example: tokyo-rain-123 | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Project.State | String | The Project lifecycle state |
| GRM.Project.Number | String | The number uniquely identifying the Project |
| GRM.Project.ID | String | The unique, user-assigned ID of the Project |
| GRM.Project.Name | String | The user-assigned display name of the Project |
| GRM.Project.CreateTime | Date | createTime - The time the resource was created |
| GRM.Project.Label | Unknown | The labels associated with this Project |
| GRM.Project.Parent.ID | String | ID of the parent resource |
| GRM.Project.Parent.Type | String | Type of the parent resource |
Command Example
grm-delete-project project_id=faramir-111
Context Example
{
"GRM.Project": {
"Name": "Faramir-Updated",
"Parent": {
"Type": "organization",
"ID": "690006273490"
},
"Number": "110336878499",
"Label": null,
"State": "DELETE_REQUESTED",
"ID": "faramir-111",
"CreateTime": "2019-01-15T12:30:21.267Z"
}
}
Human Readable Output
Project State Successfully Set To DELETE_REQUESTED
| Name | Parent | Number | ID | State | Label | CreateTime |
|---|---|---|---|---|---|---|
| Faramir-Updated | Type: organization ID: 690006273490 |
110336878499 | faramir-111 | DELETE_REQUESTED | 2019-01-15T12:30:21.267Z |
8. Restore a project
Restores the Project identified by the specified project_id, e.g., my-project-123.
Base Command
grm-undelete-project
Input
| Argument Name | Description | Required |
|---|---|---|
| project_id | The unique ID of the Project to restore. Example: tokyo-rain-123 | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GRM.Project.State | String | The Project lifecycle state |
| GRM.Project.Number | String | The number uniquely identifying the Project |
| GRM.Project.ID | String | The unique, user-assigned ID of the Project |
| GRM.Project.Name | String | The user-assigned display name of the Project |
| GRM.Project.CreateTime | Date | The time the resource was created |
| GRM.Project.Label | Unknown | The labels associated with this Project |
| GRM.Project.Parent.ID | String | ID of the parent resource |
| GRM.Project.Parent.Type | String | Type of the parent resource |
Command Example
grm-undelete-project project_id=faramir-111
Context Example
{
"GRM.Project": {
"Name": "Faramir-Updated",
"Parent": {
"Type": "organization",
"ID": "690006273490"
},
"Number": "110336878499",
"Label": null,
"State": "ACTIVE",
"ID": "faramir-111",
"CreateTime": "2019-01-15T12:30:21.267Z"
}
}
Human Readable Output
Project State Successfully Set To ACTIVE
| Name | Parent | Number | ID | State | Label | CreateTime |
|---|---|---|---|---|---|---|
| Faramir-Updated | Type: organization ID: 690006273490 |
110336878499 | faramir-111 | ACTIVE | 2019-01-15T12:30:21.267Z |
Configuration parameters
project_id— Project ID (required)private_key_id— Private Key IDprivate_key_id_creds—private_key— Private Keyprivate_key_creds—client_email— Client Emailclient_id— Client IDclient_email_creds— Client Emailclient_x509_cert_url— Client X509 Cert URL (required)proxy— Use system proxy settingsinsecure— Trust any certificate (not secure)
Commands (8)
-
grm-create-projectRequest that new Project resource be created with the user-specified values passed as command arguments.
-
grm-delete-projectMarks the Project identified by the specified project_id to be deleted, e.g., my-project-123.
-
grm-get-organizationFetches an Organization resource identified by the specified resource name.
-
grm-get-projectRetrieves the Project by the specified project_id, e.g., my-project-123.
-
grm-list-projectsLists projects that are visible to the user and satisfies the specified filter. Projects are returned in an unspecified order.
-
grm-search-organizationsSearches Organization resources that are visible to the user and satisfies the specified filter. Organizations are returned in an unspecified order. New Organizations do not necessarily appear at the end of the results.
-
grm-undelete-projectRestores the Project identified by the specified project_id, e.g., my-project-123.
-
grm-update-projectUpdates the attributes of the Project identified by the specified project_id. Currently the only fields that can be updated are the project name and labels.
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 import json import time import urllib.parse import httplib2 import googleapiclient from oauth2client import service_account from googleapiclient import discovery """ IMPORTS """ """ GLOBALS/PARAMS """ # Params for assembling object of the Service Account Credentials File Contents PARAMS = demisto.params() SERVICE_ACT_PROJECT_ID = PARAMS.get("project_id") PRIVATE_KEY_ID = PARAMS.get("private_key_id_creds", {}).get("password") or PARAMS.get("private_key_id") PRIVATE_KEY = PARAMS.get("private_key_creds", {}).get("password") or PARAMS.get("private_key") CLIENT_EMAIL = PARAMS.get("client_email_creds", {}).get("identifier") or PARAMS.get("client_email") CLIENT_ID = PARAMS.get("client_email_creds", {}).get("password") or PARAMS.get("client_id") CLIENT_X509_CERT_URL = PARAMS.get("client_x509_cert_url") PROXY = PARAMS.get("proxy") DISABLE_SSL = PARAMS.get("insecure") AUTH_JSON = { "type": "service_account", # guardrails-disable-line "project_id": SERVICE_ACT_PROJECT_ID, "private_key_id": PRIVATE_KEY_ID, "private_key": PRIVATE_KEY.replace("\\n", "\n"), "client_email": CLIENT_EMAIL, "client_id": CLIENT_ID, "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": CLIENT_X509_CERT_URL, } # Params for constructing googleapiclient service object API_VERSION = "v1" GRM = "cloudresourcemanager" SCOPE = ["https://www.googleapis.com/auth/cloud-platform"] """ HELPER FUNCTIONS """ # disable-secrets-detection-start def get_http_client_with_proxy(): proxies = handle_proxy() if not proxies or not proxies["https"]: raise Exception("https proxy value is empty. Check Demisto server configuration") https_proxy = proxies["https"] if not https_proxy.startswith("https") and not https_proxy.startswith("http"): https_proxy = "https://" + https_proxy parsed_proxy = urllib.parse.urlparse(https_proxy) proxy_info = httplib2.ProxyInfo( proxy_type=httplib2.socks.PROXY_TYPE_HTTP, # disable-secrets-detection proxy_host=parsed_proxy.hostname, proxy_port=parsed_proxy.port, proxy_user=parsed_proxy.username, proxy_pass=parsed_proxy.password, ) return httplib2.Http(proxy_info=proxy_info, disable_ssl_certificate_validation=DISABLE_SSL) # disable-secrets-detection-end def get_credentials_obj(): """Gets valid user credentials from storage. Returns: Credentials, the obtained credential. """ cred = service_account.ServiceAccountCredentials.from_json_keyfile_dict(AUTH_JSON, scopes=SCOPE) # type: ignore return cred.create_delegated(CLIENT_EMAIL) def build_and_authenticate(): """ Return a service object via which can call GRM API. Use the service_account credential file generated in the Google Cloud Platform to build the Google Resource Manager API Service object. returns: service Google Resource Manager API Service object via which commands in the integration will make API calls """ service_credentials = get_credentials_obj() if PROXY or DISABLE_SSL: http_client = service_credentials.authorize(get_http_client_with_proxy()) return discovery.build(GRM, API_VERSION, http=http_client) else: handle_proxy() return discovery.build(GRM, API_VERSION, credentials=service_credentials) def make_project_body(project_body): """ Create and return the project body argument used when calling the GRM API to create or update a project. returns: (dict) body dict object formatted to be used in the create or update API call """ keys = list(project_body.keys()) body = {} if "project_id" in keys: body["projectId"] = project_body["project_id"] if "parent_type" in keys and "parent_id" in keys: body["parent"] = {"type": project_body["parent_type"], "id": project_body["parent_id"]} if "name" in keys: body["name"] = project_body["name"] if "label_keys" in keys and "label_values" in keys: label_keys = argToList(project_body["label_keys"]) label_values = argToList(project_body["label_values"]) if len(label_keys) != len(label_values): err_msg = ( "Label attrs array and Label values array do not match" " in length.\nThese arrays need to match in length because " "each string in label_keys is assigned the value of the " "string in the corresponding index in the label_values array." ) return_error(err_msg) else: body["labels"] = {} for lbl_key, lbl_val in zip(label_keys, label_values): body["labels"][lbl_key] = lbl_val return body def poll_operation(operation): """ Query status of long running operation and return results if completed. parameter: (Operation) operation operation object returned from calls to the API that have a long execution time raises: Exception if long executing operation results in an error then raises an Exception that the operation was unsuccessful returns: (Project) response dict object representation of a Project Resource """ name = operation.get("name") while not operation.get("done"): # delay 1 second and then retry and see if the operation finished time.sleep(1) service = build_and_authenticate() # get the latest state of the long-running operation operation = service.operations().get(name=name).execute() if not operation.get("error"): return operation.get("response") else: exc = operation.get("error") err_code = exc.get("code") err_msg = exc.get("message") full_err_msg = f"error code: {err_code}\nerror message: {err_msg}" return_error(full_err_msg) # noqa: RET503 """ MAIN FUNCTIONS """ def test_module(): """If the list_projects_command executes successfully then the test completed and returns 'ok'""" build_and_authenticate() demisto.results("ok") def create_project(service, project_body): """Build service object and return the result of calling the API 'create' function for the projects resource.""" body = make_project_body(project_body) operation = service.projects().create(body=body).execute() # Get back result of long-running operation response = poll_operation(operation) return response def create_project_command(service): """ Create a project in the Google Cloud Platform. demisto parameter: (string) project_id The unique ID of the Project to create demisto parameter: (string) name The name to give the new Project demisto parameter: (string) parent_id The id of the parent resource demisto parameter: (string) parent_type The resource type the parent_id is for demisto parameter: (list) label_keys The label keys to associate with the new Project demisto parameter: (list) label_values The label values to associate with the new Project. The values are assigned to their corresponding indexed key in label_keys returns: The new Project resource object """ args = demisto.args() response = create_project(service, args) # Parse response into context context = { "Name": response.get("name"), "ID": response.get("projectId"), "Number": response.get("projectNumber"), "State": response.get("lifecycleState"), "CreateTime": response.get("createTime"), "Parent": {"ID": response.get("parent").get("id"), "Type": response.get("parent").get("type")}, "Label": response.get("labels"), } md = tableToMarkdown("Google Cloud Project Successfully Created", context) demisto.results( { "Type": entryTypes["note"], "Contents": response, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Project(val.ID && val.ID === obj.ID)": context}, } ) def delete_project(service, project_id): """Build service object and return the result of calling the API 'delete' function for the projects resource.""" operation = service.projects().delete(projectId=project_id).execute() return operation def delete_project_command(service): """ Deletes the specified project. Set the lifcycleState attribute of a specified project to DELETE_REQUESTED. demisto parameter: (string) project_id The unique ID of the Project to restore returns: Deleted project resource object """ project_id = demisto.args()["project_id"] response = delete_project(service, project_id) if not response: response = get_project(service, project_id) # Parse response into context context = { "Name": response.get("name"), "ID": response.get("projectId"), "Number": response.get("projectNumber"), "State": response.get("lifecycleState"), "CreateTime": response.get("createTime"), "Parent": {"ID": response.get("parent").get("id"), "Type": response.get("parent").get("type")}, "Label": response.get("labels"), } md = tableToMarkdown("Project State Successfully Set To DELETE_REQUESTED", context) demisto.results( { "Type": entryTypes["note"], "Contents": response, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Project(val.ID && val.ID === obj.ID)": context}, } ) else: return_error(f"Unexpected return object from {demisto.command()} execution. Results uncertain.") def undelete_project(service, project_id): """Build service object and return the result of calling the API 'undelete' function for the projects resource.""" operation = service.projects().undelete(projectId=project_id).execute() return operation def undelete_project_command(service): """ Restores the specified project. Sets the lifcycleState attribute of a specified project back to ACTIVE. demisto parameter: (string) project_id The unique ID of the Project to restore returns: Restored project resource object """ project_id = demisto.args()["project_id"] response = undelete_project(service, project_id) if not response: response = get_project(service, project_id) # Parse response into context context = { "Name": response.get("name"), "ID": response.get("projectId"), "Number": response.get("projectNumber"), "State": response.get("lifecycleState"), "CreateTime": response.get("createTime"), "Parent": {"ID": response.get("parent").get("id"), "Type": response.get("parent").get("type")}, "Label": response.get("labels"), } md = tableToMarkdown("Project State Successfully Set To ACTIVE", context) demisto.results( { "Type": entryTypes["note"], "Contents": response, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Project(val.ID && val.ID === obj.ID)": context}, } ) else: return_error(f"Unexpected return object from {demisto.command()} execution. Results uncertain.") def get_project(service, project_id): """Build service object and return the result of calling the API 'get' function for the projects resource.""" operation = service.projects().get(projectId=project_id).execute() return operation def get_project_command(service): """ Retrieves the Project identified by the specified project_id. demisto parameter: (string) project_id The unique ID of the Project to fetch returns: The project resource object specified by the project_id """ project_id = demisto.args().get("project_id") response = get_project(service, project_id) # Parse response into context context = { "Name": response.get("name"), "ID": response.get("projectId"), "Number": response.get("projectNumber"), "State": response.get("lifecycleState"), "CreateTime": response.get("createTime"), "Parent": {"ID": response.get("parent").get("id"), "Type": response.get("parent").get("type")}, "Label": response.get("labels"), } md = tableToMarkdown("Details of Fetched Google Cloud Project", context) demisto.results( { "Type": entryTypes["note"], "Contents": response, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Project(val.ID && val.ID === obj.ID)": context}, } ) def list_projects(service, filter_list): """Build service object and return the result of calling the API 'list' function for the projects resource.""" operation = service.projects().list(filter=filter_list).execute() return operation def list_projects_command(service): """ Lists Projects that are visible to the user and satisfy the specified filter if one is provided. demisto parameter: (string) filter -- optional An expression for filtering the results of the request returns: Project resource objects that are visible to the user and satisfy the specified filter """ filter_list = demisto.args().get("filter") if "filter" in demisto.args() else None response = list_projects(service, filter_list) contexts = [] for project in response.get("projects", []): # Parse project into context context = { "Name": project.get("name"), "ID": project.get("projectId"), "Number": project.get("projectNumber"), "State": project.get("lifecycleState"), "CreateTime": project.get("createTime"), "Parent": {"ID": project.get("parent").get("id"), "Type": project.get("parent").get("type")}, "Label": project.get("labels"), } contexts.append(context) title = f"Projects Filtered by '{filter_list}'" if filter_list else "All Projects" md = tableToMarkdown(title, contexts) entry = { "Type": entryTypes["note"], "Contents": response, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Project(val.ID && val.ID === obj.ID)": contexts}, } demisto.results(entry) def update_project(service, project_id, project_body): """Build service object and return the result of calling the API 'update' function for the projects resource.""" operation = service.projects().update(projectId=project_id, body=project_body).execute() return operation def update_project_command(service): """ Updates the attributes of the Project identified by the specified project_id. demisto parameter: (string) project_id The unique ID of the Project to update demisto parameter: (string) name The string to update the Project name with demisto parameter: (string) parent_id The id of the parent resource demisto parameter: (string) parent_type The resource type the parent_id is for demisto parameter: (list) label_keys The label keys to associate with this Project demisto parameter: (list) label_values The label values to associate with this Project. The values are assigned to their corresponding indexed key in label_keys returns: The updated Project resource object """ project_id = demisto.args().get("project_id") project_body = demisto.args() project_body = make_project_body(project_body) response = update_project(service, project_id, project_body) # Parse response into context context = { "Name": response.get("name"), "ID": response.get("projectId"), "Number": response.get("projectNumber"), "State": response.get("lifecycleState"), "CreateTime": response.get("createTime"), "Parent": {"ID": response.get("parent").get("id"), "Type": response.get("parent").get("type")}, "Label": response.get("labels"), } md = tableToMarkdown("Details of Updated Google Cloud Project", context) demisto.results( { "Type": entryTypes["note"], "Contents": response, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Project(val.ID && val.ID === obj.ID)": context}, } ) def search_organizations(service, req_body): """ Build service object and return the result of calling the API 'search' function for the organizations resource. """ operation = service.organizations().search(body=req_body).execute() return operation def search_organizations_command(service): """ Searches Organization resources that are visible to the user and satisfy the specified filter (if provided). demisto parameter: (number) pageSize -- optional The maximum number of Organizations to return in the response demisto parameter: (string) pageToken -- optional A pagination token returned from a previous call to organizations.search() that indicates from where listing should continue demisto parameter: (string) filter -- optional Used to filter the Organizations to return in the response returns: List of Organization resource objects that are visible to the user and satisfy the specified filter """ args = demisto.args() # make request body req_body = { "pageSize": args.get("page_size") if "page_size" in args else None, "pageToken": args.get("page_token") if "page_token" in args else None, "filter": args.get("filter") if "filter" in args else None, } contexts = [] contents = [] next_page = True # continue calling the API with the appropriate pageToken argument while there are still results to be received # from the search organizations API call - this is useful in the case that a pageSize argument was given in this # command that was less than the total amount of results returned from the original call to the API while next_page: response = search_organizations(service, req_body) contents.append(response) for organization in response.get("organizations", []): # Parse organization into context context = { "Name": organization.get("name"), "State": organization.get("lifecycleState"), "CreateTime": organization.get("creationTime"), "Owner": {"CustomerID": organization.get("owner").get("directoryCustomerId")}, } contexts.append(context) if "nextPageToken" not in response: next_page = False else: req_body["pageToken"] = response["nextPageToken"] md = tableToMarkdown("Organizations", contexts) entry = { "Type": entryTypes["note"], "Contents": contents, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Organization(val.Name && val.Name === obj.Name)": contexts}, } demisto.results(entry) def get_organization(service, name): """ Build service object and return the result of calling the API 'get' function for the organizations resource. parameter: (string) name name of the Organization in format <type/number> e.g. 'organizations/1245345444' returns: (Organization) operation The response from calling the API that takes the form of a Organization object """ operation = service.organizations().get(name=name).execute() return operation def get_organization_command(service): """ Fetches an Organization resource identified by the specified resource name. demisto parameter: (string) name name of the Organization in format <type/number> e.g. 'organizations/1245345444' returns: The organization object with its associated fields """ name = demisto.args().get("name") response = get_organization(service, name) # Parse response into context context = { "Name": response.get("name"), "State": response.get("lifecycleState"), "CreateTime": response.get("creationTime"), "Owner": {"CustomerID": response.get("owner").get("directoryCustomerId")}, } md = tableToMarkdown("Details of Fetched Organization", context) demisto.results( { "Type": entryTypes["note"], "Contents": response, "ContentsFormat": formats["json"], "ReadableContentsFormat": formats["markdown"], "HumanReadable": md, "EntryContext": {"GRM.Organization(val.Name && val.Name === obj.Name)": context}, } ) """ COMMANDS MANAGER / SWITCH PANEL """ def main(): # Command Switch Panel commands = { "grm-create-project": create_project_command, "grm-delete-project": delete_project_command, "grm-get-project": get_project_command, "grm-list-projects": list_projects_command, "grm-update-project": update_project_command, "grm-search-organizations": search_organizations_command, "grm-get-organization": get_organization_command, "grm-undelete-project": undelete_project_command, } LOG(f"Command being called is {demisto.command()}") try: if demisto.command() == "test-module": # This is the call made when pressing the integration test button. test_module() elif demisto.command() in list(commands.keys()): service = build_and_authenticate() commands[demisto.command()](service) except Exception as exc: # Output HttpError errors from googleapiclient to the warroom nicely if isinstance(exc, googleapiclient.errors.HttpError): if exc.resp.get("content-type").startswith("application/json"): # pylint: disable=no-member err_json = json.loads(exc.content.decode("utf-8")) # pylint: disable=no-member error_code = dict_safe_get(err_json, ["error", "code"]) error_msg = dict_safe_get(err_json, ["error", "message"]) error_reason = dict_safe_get(err_json, ["error", "errors", 0, "reason"]) error_status = dict_safe_get(err_json, ["error", "status"]) full_err_msg = f"error code: {error_code}\n{error_msg}\nreason: {error_reason}\nstatus: {error_status}" return_error(full_err_msg) else: return_error(str(exc)) if __name__ in ("__builtin__", "builtins"): main()