Google Cloud Functions

Google Cloud Functions is an event-driven serverless compute platform that enables you to run your code locally or in the cloud without having to provision servers.

Utilities · Google Cloud Functions

Details

IDGoogle Cloud Functions
ProviderGoogle
CategoryUtilities
From Version5.0.0
Docker Imagedemisto/google-api-py3:1.0.0.10182333
Supported ModulesAgentix XSIAM

README

Google Cloud Functions is an event-driven serverless compute platform that enables you to run your code locally or in the cloud without having to provision servers.
This integration was integrated and tested with API version 1 of Google Cloud Functions

Configure Google Cloud Functions in Cortex

Parameter Description Required
credentials_json Service account private key file contents (JSON) True
project_id Default project ID False
region Default region False
proxy Use system proxy settings False
insecure Trust any certificate (not secure) False

Commands

You can execute these commands from the 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.

google-cloud-functions-list


Lists all Google Cloud functions.

Base Command

google-cloud-functions-list

Input
Argument Name Description Required
project_id The project ID the Google Cloud function is in. Default is the instance's project. Optional
region The region of the Google Cloud function. Default is all regions. You can get a full list of regions using the google-cloud-function-regions-list command. Optional
Context Output
Path Type Description
GoogleCloudFunctions.Function.name String A user-defined name of the Google Cloud function.
GoogleCloudFunctions.Function.status String Status of the Google Cloud function deployment. The status can be: ACTIVE, OFFLINE, DEPLOY_IN_PROGRESS, DELETE_IN_PROGRESS, UNKNOWN.
GoogleCloudFunctions.Function.labels String Labels associated with this Google Cloud function.
GoogleCloudFunctions.Function.runtime String The time in which to run the Google Cloud function.
Command Example

##### Context Example

{
“GoogleCloudFunctions”: {
“Function”: [
{
“availableMemoryMb”: 128,
“entryPoint”: “hello_world”,
“httpsTrigger”: {
“url”: “www.example.com”
},
“ingressSettings”: “ALLOW_ALL”,
“labels”: {
“deployment-tool”: “console-cloud”
},
“name”: “projects/project/locations/us-central1/functions/demisto-func”,
“runtime”: “python37”,
“serviceAccountEmail”: “email”,
“sourceUploadUrl”: “”,
“status”: “ACTIVE”,
“timeout”: “60s”,
“updateTime”: “2020-04-05T12:43:29.610Z”,
“versionId”: “1”
}
]
}
}


##### Human Readable Output

### Functions in project "gcp-integrations" and region "us-central1"

|name|httpsTrigger|status|entryPoint|timeout|availableMemoryMb|serviceAccountEmail|updateTime|versionId|labels|sourceUploadUrl|runtime|ingressSettings|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| projects/project/locations/us-central1/functions/demisto-func | url: www.example.com | ACTIVE | hello_world | 60s | 128 | email | 2020-04-05T12:43:29.610Z | 1 | deployment-tool: console-cloud |  | python37 | ALLOW_ALL |

### google-cloud-function-regions-list

***
Lists all regions in the project.

##### Base Command

`google-cloud-function-regions-list`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| project_id | The project ID the Google Cloud function is in. Default is the instance's project. | Optional |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| GoogleCloudFunctions.Region.locationId | String | The location ID of the region. |
| GoogleCloudFunctions.Region.name | String | The full name of the region. |
| GoogleCloudFunctions.Region.labels | String | The labels for the region. |

##### Command Example

```!google-cloud-function-regions-list```

##### Context Example

{
“GoogleCloudFunctions”: {
“Region”: [
{
“labels”: {
“cloud.googleapis.com/region”: “europe-west1”
},
“locationId”: “europe-west1”,
“name”: “projects/gcp-integrations/locations/europe-west1”
},
{
“labels”: {
“cloud.googleapis.com/region”: “europe-west3”
},
“locationId”: “europe-west3”,
“name”: “projects/gcp-integrations/locations/europe-west3”
},
{
“labels”: {
“cloud.googleapis.com/region”: “europe-west2”
},
“locationId”: “europe-west2”,
“name”: “projects/gcp-integrations/locations/europe-west2”
},
{
“labels”: {
“cloud.googleapis.com/region”: “us-central1”
},
“locationId”: “us-central1”,
“name”: “projects/gcp-integrations/locations/us-central1”
},
{
“labels”: {
“cloud.googleapis.com/region”: “us-east1”
},
“locationId”: “us-east1”,
“name”: “projects/gcp-integrations/locations/us-east1”
},
{
“labels”: {
“cloud.googleapis.com/region”: “us-east4”
},
“locationId”: “us-east4”,
“name”: “projects/gcp-integrations/locations/us-east4”
},
{
“labels”: {
“cloud.googleapis.com/region”: “asia-northeast1”
},
“locationId”: “asia-northeast1”,
“name”: “projects/gcp-integrations/locations/asia-northeast1”
},
{
“labels”: {
“cloud.googleapis.com/region”: “asia-east2”
},
“locationId”: “asia-east2”,
“name”: “projects/gcp-integrations/locations/asia-east2”
}
]
}
}


##### Human Readable Output

### Regions in project "gcp-integrations"

|locationId|name|labels|
|---|---|---|
| europe-west1 | projects/gcp-integrations/locations/europe-west1 | cloud.googleapis.com/region: europe-west1 |
| europe-west3 | projects/gcp-integrations/locations/europe-west3 | cloud.googleapis.com/region: europe-west3 |
| europe-west2 | projects/gcp-integrations/locations/europe-west2 | cloud.googleapis.com/region: europe-west2 |
| us-central1 | projects/gcp-integrations/locations/us-central1 | cloud.googleapis.com/region: us-central1 |
| us-east1 | projects/gcp-integrations/locations/us-east1 | cloud.googleapis.com/region: us-east1 |
| us-east4 | projects/gcp-integrations/locations/us-east4 | cloud.googleapis.com/region: us-east4 |
| asia-northeast1 | projects/gcp-integrations/locations/asia-northeast1 | cloud.googleapis.com/region: asia-northeast1 |
| asia-east2 | projects/gcp-integrations/locations/asia-east2 | cloud.googleapis.com/region: asia-east2 |

### google-cloud-function-get-by-name

***
Gets the details of a specific Google Cloud function.

##### Base Command

`google-cloud-function-get-by-name`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| project_id | The project ID the Google Cloud function is in. Default is the instance's project. | Optional |
| region | The region of the Google Cloud function. You can get a full list of regions using the `google-cloud-function-regions-list` command. Default is all regions. | Optional |
| function_name | The name of the function. | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| GoogleCloudFunctions.Function.name | String | A user\-defined name of the Google Cloud function. |
| GoogleCloudFunctions.Function.status | String | Status of the Google Cloud function deployment. The status can be ACTIVE, OFFLINE, DEPLOY\_IN\_PROGRESS, DELETE\_IN\_PROGRESS, UNKNOWN. |
| GoogleCloudFunctions.Function.labels | String | The labels associated with this Google Cloud Function. |
| GoogleCloudFunctions.Function.runtime | String | The time in which to run the Google Cloud function. |

##### Command Example

```!google-cloud-function-get-by-name function_name="demisto-func"```

##### Context Example

{
“GoogleCloudFunctions”: {
“Function”: {
“availableMemoryMb”: 128,
“entryPoint”: “hello_world”,
“httpsTrigger”: {
“url”: “”
},
“ingressSettings”: “ALLOW_ALL”,
“labels”: {
“deployment-tool”: “console-cloud”
},
“name”: “projects/project/locations/us-central1/functions/demisto-func”,
“runtime”: “python37”,
“serviceAccountEmail”: “email”,
“sourceUploadUrl”: “”,
“status”: “ACTIVE”,
“timeout”: “60s”,
“updateTime”: “2020-04-05T12:43:29.610Z”,
“versionId”: “1”
}
}
}


##### Human Readable Output

### Here are the details for demisto-func

|name|httpsTrigger|status|entryPoint|timeout|availableMemoryMb|serviceAccountEmail|updateTime|versionId|labels|sourceUploadUrl|runtime|ingressSettings|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| projects/project/locations/us-central1/functions/demisto-func | url: www.example.com | ACTIVE | hello_world | 60s | 128 | email | 2020-04-05T12:43:29.610Z | 1 | deployment-tool: console-cloud |  | python37 | ALLOW_ALL |

### google-cloud-function-execute

***
Executes a Google Cloud function.

##### Base Command

`google-cloud-function-execute`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| function_name | The name of the Google Cloud function to execute. | Required |
| region | The region of the Google Cloud function. Default is all regions. You can get a full list of regions using the `google-cloud-function-regions-list` command. | Optional |
| parameters | The Google Cloud function parameters in a key:value format. Multiple parameters should be comma-separated (i.e., key1:value1,key2:value2). | Optional |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| GoogleCloudFunctions.Execution.executionId | String | Execution ID of the Google Cloud function invocated. |
| GoogleCloudFunctions.Execution.result | String | Result populated for successful execution of a synchronous Google Cloud function. It will not be populated if the Google Cloud function does not return a result through context. |
| GoogleCloudFunctions.Execution.error | String | Either a system or user\-function generated error. Set if the execution was not successful. |

##### Command Example

```!google-cloud-function-execute function_name=demisto-func parameters=message:hell\"oThere```

##### Context Example

{
“GoogleCloudFunctions”: {
“Execution”: {
“executionId”: “xp9hifb4y996”,
“result”: “hell"oThere”
}
}
}
```

Human Readable Output

Execution details for demisto-func

executionId result
xp9hifb4y996 hell”oThere

Configuration parameters

  • credentials_json — Service account private key file contents (JSON)
  • project_id_creds — Default project ID
  • project_id — Default project ID
  • region — Default region
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)

Commands (4)

  • google-cloud-function-execute

    Executes a Google Cloud function.

  • google-cloud-function-get-by-name

    Gets the details of a specific Google Cloud function.

  • google-cloud-function-regions-list

    Lists all regions in the project.

  • google-cloud-functions-list

    Lists all Google Cloud functions.

import demistomock as demisto
from CommonServerPython import *  # noqa: E402 lgtm [py/polluting-import]

from CommonServerUserPython import *  # noqa: E402 lgtm [py/polluting-import]

""" IMPORTS """
import json
import urllib.parse

import httplib2
from apiclient import discovery
from oauth2client import service_account


class GoogleClient:
    """
    A Client class to wrap the google cloud api library.
    """

    def __init__(
        self, service_name: str, service_version: str, client_secret: str, scopes: list, proxy: bool, insecure: bool, **kwargs
    ):
        """
        :param service_name: The name of the service. You can find this and the service  here
         https://github.com/googleapis/google-api-python-client/blob/master/docs/dyn/index.md
        :param service_version:The version of the API.
        :param client_secret: A string of the credentials.json generated
        :param scopes: The scope needed for the project. Might be different per function.
        (i.e. ['https://www.googleapis.com/auth/cloud-platform'])
        :param proxy:
        :param insecure:
        :param kwargs:
        """
        self.project = kwargs.get("project", "")
        self.region = kwargs.get("region", "-")
        credentials = service_account.ServiceAccountCredentials.from_json_keyfile_dict(client_secret, scopes=scopes)
        if proxy or insecure:
            http_client = credentials.authorize(self.get_http_client_with_proxy(proxy, insecure))
            self.service = discovery.build(service_name, service_version, http=http_client)
        else:
            self.service = discovery.build(service_name, service_version, credentials=credentials)

    # disable-secrets-detection-start
    @staticmethod
    def get_http_client_with_proxy(proxy, insecure):
        """
        Create an http client with proxy with whom to use when using a proxy.
        :param proxy: Whether to use a proxy.
        :param insecure: Whether to disable ssl and use an insecure connection.
        :return:
        """
        if proxy:
            proxies = handle_proxy()
            https_proxy = proxies.get("https")
            http_proxy = proxies.get("http")
            proxy_conf = https_proxy if https_proxy else http_proxy
            # if no proxy_conf - ignore proxy
            if proxy_conf:
                if not proxy_conf.startswith("https") and not proxy_conf.startswith("http"):
                    proxy_conf = "https://" + proxy_conf
                parsed_proxy = urllib.parse.urlparse(proxy_conf)
                proxy_info = httplib2.ProxyInfo(
                    proxy_type=httplib2.socks.PROXY_TYPE_HTTP,
                    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=insecure)
        return httplib2.Http(disable_ssl_certificate_validation=insecure)

    # disable-secrets-detection-end

    def functions_list(self, region=None, project_id=None):
        if project_id:
            self.project = project_id
        if region:
            self.region = region
        parent = f"projects/{self.project}/locations/{self.region}"
        return self.service.projects().locations().functions().list(parent=parent).execute()

    def region_list(self, project_id):
        if project_id:
            self.project = project_id
        name = f"projects/{self.project}"
        return self.service.projects().locations().list(name=name).execute()

    def function_by_name(self, function_name, region=None, project_id=None):
        if project_id:
            self.project = project_id
        if region:
            self.region = region
        name = f"projects/{self.project}/locations/{self.region}/functions/{function_name}"
        return self.service.projects().locations().functions().get(name=name).execute()

    def execute_function(self, function_name: str, data: str, region, project_id):
        if project_id:
            self.project = project_id
        if region:
            self.region = region
        name = f"projects/{self.project}/locations/{self.region}/functions/{function_name}"
        body = {"data": data}
        return self.service.projects().locations().functions().call(name=name, body=body).execute()


"""COMMAND FUNCTIONS"""


def functions_list_command(client: GoogleClient, args: dict):
    region = client.region
    project_id = client.project
    res = client.functions_list(region, project_id)
    functions = res.get("functions", [])
    if not functions:
        return "No functions found.", {}, {}
    keys = list(functions[0].keys())
    keys.remove("name")
    disp_region = "All" if client.region == "-" else client.region
    hr = tableToMarkdown(f'Functions in project "{client.project}" and region "{disp_region}"', functions, ["name"] + keys)
    ec = {"GoogleCloudFunctions.Function(val.name && val.name == obj.name)": functions}
    return hr, ec, res


def region_list_command(client: GoogleClient, args: dict):
    project_id = args.get("project_id")
    res = client.region_list(project_id)
    regions = res.get("locations", [])
    hr = tableToMarkdown(f'Regions in project "{client.project}"', regions, ["locationId", "name", "labels"])
    ec = {"GoogleCloudFunctions.Region(val.locationId && val.locationId == obj.locationId)": regions}
    return hr, ec, res


def get_function_by_name_command(client: GoogleClient, args: dict):
    function_name = args.get("function_name", "")
    project_id = args.get("project_id")
    region = args.get("region")
    res = client.function_by_name(function_name, region, project_id)
    keys = list(res.keys())
    keys.remove("name")
    hr = tableToMarkdown(f'Here are the details for {args.get("function_name")}:', res, ["name"] + keys)
    ec = {"GoogleCloudFunctions.Function(val.name && val.name == obj.name)": res}
    return hr, ec, res


def execute_function_command(client: GoogleClient, args: dict):
    project_id = args.get("project_id")
    region = args.get("region")
    function_name = args.get("function_name", "")
    parameters = format_parameters(args.get("parameters", ""))
    res = client.execute_function(function_name, parameters, region, project_id)
    hr = tableToMarkdown(f'Execution details for {args.get("function_name")}:', res)
    ec = {"GoogleCloudFunctions.Execution(val.executionId && val.executionId == obj.executionId)": res}
    return hr, ec, res


"""HELPER FUNCTIONS"""


@logger
def format_parameters(parameters: str) -> str:
    """
    Receives a key:value string and retuns a dictionary string ({"key":"value"}). In the process strips trailing and
    leading spaces.
    :param parameters: The key-value-list
    :return:
    """
    if not parameters:
        return "{}"
    pairs = []
    for item in parameters.split(","):
        try:
            key, value = item.split(":")
        except ValueError:
            raise ValueError(f"Got unexpected parameters {item}.")
        pairs.append((key.strip(), value.strip()))
    return json.dumps(dict(pairs))


def resolve_default_region(region: str):
    # when region is empty, set it to '-' meaning all regions
    # note : demisto.params().get('region','-') did not worked on Demisto
    if not region:
        # from Google API : If you want to list functions in all locations, use "-" in place of a location
        return "-"
    return region


def resolve_default_project_id(project: str, credentials_json: dict):
    if not project:
        # when project_id is empty, get it from credentials_json
        no_project_id_in_credentials = "project_id" not in credentials_json
        if no_project_id_in_credentials:
            # when not provided project id at all, return error
            return_error("Service account private key file contents does not have a project id")
        project = credentials_json["project_id"]
    return project


def main():
    params = demisto.params()
    credentials_json = json.loads(params.get("project_id_creds", {}).get("password") or params.get("credentials_json", {}))
    project = params.get("project_id_creds", {}).get("identifier") or params.get("project_id")
    project = resolve_default_project_id(project, credentials_json)
    region = params.get("region")
    region = resolve_default_region(region)
    proxy = params.get("proxy", False)
    insecure = params.get("insecure", False)
    scopes = ["https://www.googleapis.com/auth/cloud-platform"]
    client = GoogleClient("cloudfunctions", "v1", credentials_json, scopes, proxy, insecure, project=project, region=region)

    commands = {
        "google-cloud-functions-list": functions_list_command,
        "google-cloud-function-regions-list": region_list_command,
        "google-cloud-function-get-by-name": get_function_by_name_command,
        "google-cloud-function-execute": execute_function_command,
    }

    """EXECUTION CODE"""
    cmd_func = demisto.command()
    LOG(f"Command being called is {cmd_func}")
    try:
        if cmd_func == "test-module":
            functions_list_command(client, {})
            demisto.results("ok")
        else:
            hr, outputs, raw = commands[cmd_func](client, demisto.args())
            return_outputs(hr, outputs, raw)

    except Exception as e:
        return_error(f"Failed to execute {cmd_func} command. Error: {e}")
        raise


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()