Skip to content

Commit

Permalink
Internal change
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 545733180
  • Loading branch information
Chronicle Team authored and bumblebee211196 committed Jul 6, 2023
1 parent 48ba649 commit f1d42da
Show file tree
Hide file tree
Showing 41 changed files with 6,838 additions and 41 deletions.
21 changes: 21 additions & 0 deletions common/chronicle_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
default_cred_file_path = os.path.join(CHRONICLE_CLI_ROOT_DIR,
"chronicle_credentials.json")
AUTHORIZATION_SCOPES = ["https://www.googleapis.com/auth/chronicle-backstory"]
DATAPLANE_AUTHORIZATION_SCOPES = [
"https://www.googleapis.com/auth/cloud-platform"
]


def initialize_http_session(credential_file_path: AnyStr) -> Any:
Expand All @@ -44,3 +47,21 @@ def initialize_http_session(credential_file_path: AnyStr) -> Any:
filename=os.path.abspath(credential_file_path or default_cred_file_path),
scopes=AUTHORIZATION_SCOPES)
return requests.AuthorizedSession(credentials)


def initialize_dataplane_http_session(credential_file_path: AnyStr) -> Any:
"""Initalizes an authorized HTTP session for Dataplane APIs, based on the given credential.
Args:
credential_file_path: Absolute or relative path to a JSON file containing
private OAuth 2.0 credentials of a Google Cloud Platform service account.
Default path is ".chronicle_credentials.json" in the .chronicle_cli
directory inside user's home directory.
Returns:
HTTP session object to send authorized requests and receive responses.
"""
credentials = service_account.Credentials.from_service_account_file(
filename=os.path.abspath(credential_file_path or default_cred_file_path),
scopes=DATAPLANE_AUTHORIZATION_SCOPES)
return requests.AuthorizedSession(credentials)
29 changes: 29 additions & 0 deletions common/chronicle_auth_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,32 @@ def test_initialize_http_session_with_custom_json_credentials(
mock_from_service_account_file.assert_called_once_with(
filename=TEMP_SERVICE_ACCOUNT_FILE,
scopes=chronicle_auth.AUTHORIZATION_SCOPES)


@mock.patch.object(service_account.Credentials, "from_service_account_file")
def test_initialize_chronicle_http_session(mock_from_service_account_file):
"""Test to check if http session is initialize or not.
Args:
mock_from_service_account_file (mock.MagicMock): Mock object
"""
create_service_account_file()
chronicle_auth.initialize_dataplane_http_session("")
mock_from_service_account_file.assert_called_once_with(
filename=str(chronicle_auth.default_cred_file_path),
scopes=chronicle_auth.DATAPLANE_AUTHORIZATION_SCOPES)


@mock.patch.object(service_account.Credentials, "from_service_account_file")
def test_initialize_chronicle_http_session_with_custom_json_credentials(
mock_from_service_account_file):
"""Test to check if http session is initialize with custom credentials.
Args:
mock_from_service_account_file (mock.MagicMock): Mock object
"""
create_service_account_file()
chronicle_auth.initialize_dataplane_http_session(TEMP_SERVICE_ACCOUNT_FILE)
mock_from_service_account_file.assert_called_once_with(
filename=TEMP_SERVICE_ACCOUNT_FILE,
scopes=chronicle_auth.DATAPLANE_AUTHORIZATION_SCOPES)
2 changes: 1 addition & 1 deletion common/commands_utility_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_lower_or_none_none() -> None:


def test_space_separated_str() -> None:
"""Test converting of camel case sentence to space separated first letter capital.
"""Test converting of camel case sentence to space seprated first letter capital.
"""
assert commands_utility.space_separated_str('dummyTest') == 'Dummy test'

Expand Down
9 changes: 7 additions & 2 deletions common/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
from common import chronicle_auth

REGION_LIST = [
"US",
"ASIA-SOUTHEAST1",
"AUSTRALIA-SOUTHEAST1",
"EUROPE",
"EUROPE-WEST2",
"AUSTRALIA-SOUTHEAST1",
"ME-WEST1",
"US",
]

verbose_option = click.option(
Expand Down Expand Up @@ -62,3 +63,7 @@
export_option = click.option(
"--export", help="Export output to specified file path"
)

v2_option = click.option(
"--v2", is_flag=True, help="Enable v2 commands."
)
23 changes: 23 additions & 0 deletions common/uri.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
BASE_URL = "https://backstory.googleapis.com"
CHRONICLE_TEST_API_URL = "https://test-backstory.sandbox.googleapis.com"

DATAPLANE_BASE_URL = "https://{region}-chronicle.googleapis.com"
DATAPLANE_TEST_URL = "https://test-chronicle.sandbox.googleapis.com"


def get_base_url(region: str, custom_url: str, env: str = "prod") -> str:
"""Get base URL according to selected region.
Expand All @@ -37,3 +40,23 @@ def get_base_url(region: str, custom_url: str, env: str = "prod") -> str:
if env == "test":
return CHRONICLE_TEST_API_URL
return BASE_URL


def get_dataplane_base_url(region: str,
custom_url: str,
env: str = "prod") -> str:
"""Get base URL for DataPlane API according to selected region.
Args:
region (str): Region (US, EUROPE, ASIA_SOUTHEAST1, EUROPE_WEST2)
custom_url (str): Base URL to be used for API calls
env (str): Environment for API calls (prod, test)
Returns:
str: Base URL
"""
if custom_url:
return custom_url
if env == "test":
return DATAPLANE_TEST_URL
return DATAPLANE_BASE_URL.format(region=region)
4 changes: 2 additions & 2 deletions feeds/feed_schema_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def get_detailed_schema(self, user_source_type: AnyStr,
Returns:
dataclass: Consists of -
1. Display name of Source type
1. Display nane of Source type
2. Schema of Log type
3. Error message.
"""
Expand Down Expand Up @@ -254,7 +254,7 @@ def process_namespace_input(self, flattened_response: Dict[str, Any]) -> None:
self.pre_body[schema.KEY_DETAILS_NAMESPACE] = namespace

def process_labels_input(self, flattened_response: Dict[str, Any]) -> None:
"""Prompt input for labels field.
"""Prompt input for lables field.
Args:
flattened_response (Dict): Flattened response of existing feed.
Expand Down
2 changes: 1 addition & 1 deletion feeds/feed_utility_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,5 @@ def test_get_feed_display_name() -> None:


def test_get_feed_display_name_none() -> None:
"""Test feed display name if not exist in feed dictionary."""
"""Test feed display name if not exist in feed dictonary."""
assert not feed_utility.get_feed_display_name({})
6 changes: 3 additions & 3 deletions forwarders/schema_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ def process_input_detailed_schema(self,
backup_request_body (Any): Request body of existing forwarder or
collector.
each_field_mask_path (str): String containing field path from parent field
separated by ".".
seperated by ".".
"""
for each in detailed_schema:

Expand Down Expand Up @@ -393,7 +393,7 @@ def process_each_field_type(self, each: Dict[str, Any], request_body: Any,
request_body (Any): API request body.
existing_value (Any): Existing value of feilds.
each_field_mask_path (str): String containing field path from parent field
separated by ".".
seperated by ".".
"""
# Processing user input for primitive types.
if each.get(schema.KEY_FIELD_TYPE) in [
Expand Down Expand Up @@ -527,7 +527,7 @@ def populate_repeated_values(self, each_field_schema, request_body,
existing_value: Existing value of feilds. {"description": "sample",
"regexp": ".*"}.
each_field_mask_path (str): String containing field path from parent field
separated by ".".
seperated by ".".
"""
each_non_primitive_dict = {}
for each in each_field_schema.get(
Expand Down
4 changes: 2 additions & 2 deletions forwarders/schema_utility_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def test_process_input_detailed_schema_non_primitive(
========================================
========================================
======= Forwarder Configuration ========
======== Forwarder Cofiguration ========
========================================""" in output


Expand Down Expand Up @@ -390,7 +390,7 @@ def test_process_input_detailed_schema_repeated_message_fields(
Args:
confirm_patch: Mock object for click confirm.
input_patch: Mock object for click prompt.
repeated_message_fields_schema: (Fixture) Repeated fields type schema.
repeated_message_fields_schema: (Fixture) Repeated fileds type schema.
"""
schema_object = schema_utility.Schema(schema.KEY_COLLECTOR_SCHEMA, {})
confirm_patch.side_effect = [True, False]
Expand Down
2 changes: 1 addition & 1 deletion forwarders/tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def non_primitive_schema() -> Any:
"fieldPath":
"config",
"displayName":
"Forwarder Configuration",
"Forwarder Cofiguration",
"description":
"Forwarder configuration settings",
"type":
Expand Down
126 changes: 126 additions & 0 deletions parsers/commands/activate_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Activate a parser."""

import click

from common import api_utility
from common import chronicle_auth
from common import exception_handler
from common import options
from common.constants import key_constants as common_constants
from common.constants import status
from parsers import url


@click.command(name="activate_parser", help="[New]Activate a parser")
@click.argument("project_id", required=True, default="")
@click.argument("customer_id", required=True, default="")
@click.argument("log_type", required=True, default="")
@click.argument("parser_id", required=True, default="")
@options.env_option
@options.region_option
@options.verbose_option
@options.credential_file_option
@options.v2_option
@exception_handler.catch_exception()
def activate_parser(
v2: bool,
credential_file: str,
verbose: bool,
region: str,
env: str,
project_id: str,
customer_id: str,
log_type: str,
parser_id: int) -> None:
"""Activate a parser given the Parser ID.
Args:
v2 (bool): Option for enabling v2 commands.
credential_file (AnyStr): Path of Service Account JSON.
verbose (bool): Option for printing verbose output to console.
region (str): Option for selecting regions. Available options - US, EUROPE,
ASIA_SOUTHEAST1.
env (str): Option for selection environment. Available options - prod, test.
project_id (str): The GCP Project ID.
customer_id (str): The Customer ID.
log_type (str): The Log Type.
parser_id (int): The Parser ID.
Raises:
OSError: Failed to read the given file, e.g. not found, no read access
(https://docs.python.org/library/exceptions.html#os-exceptions).
ValueError: Invalid file contents.
KeyError: Required key is not present in dictionary.
TypeError: If response data is not JSON.
"""
if not v2:
click.echo("--v2 flag not provided. "
"Please provide the flag to run the new commands")
return

if not project_id:
click.echo("Project ID not provided. Please enter Porject ID")
return

if not customer_id:
click.echo("Customer ID not provided. Please enter Customer ID")
return

if not log_type:
click.echo("Log Type not provided. Please enter Log Type")
return

if not parser_id:
click.echo("Parser ID not provided. Please enter Parser ID")
return

click.echo("Activating Parser...")

resources = {
"project": project_id,
"location": region.lower(),
"instance": customer_id,
"log_type": log_type,
"parser": parser_id
}

activate_parser_url = url.get_dataplane_url(
region,
"activate_parser",
env,
resources)
client = chronicle_auth.initialize_dataplane_http_session(credential_file)
method = "POST"
response = client.request(
method, activate_parser_url, timeout=url.HTTP_REQUEST_TIMEOUT_IN_SECS)
parsed_response = api_utility.check_content_type(response.text)

if response.status_code != status.STATUS_OK:
click.echo(
f"Error while activating parser.\n"
f"Response Code: {response.status_code}\n"
f"Error: "
f"{parsed_response[common_constants.KEY_ERROR][common_constants.KEY_MESSAGE]}"
)
return

click.echo("Parser activated successfully.")

if verbose:
api_utility.print_request_details(
activate_parser_url, method, None, parsed_response
)
Loading

0 comments on commit f1d42da

Please sign in to comment.