Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make sure module parsing works #8

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,6 @@ cython_debug/
.terraform.lock.hcl
terraform.tfstate
terraform.tfstate.backup
!sdks/python/tests/data/terraform.tfstate
!sdks/python/tests/data/gcp/terraform.tfstate
testing/
coverage.xml
1 change: 0 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ terrabridge
gcp-resources/pubsub
gcp-resources/secret_manager


|license| |CI| |Python version| |codecov|

.. |license| image:: https://img.shields.io/pypi/l/terrabridge.svg
Expand Down
4 changes: 0 additions & 4 deletions sdks/python/examples/gcp/postgres/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,19 @@ provider "google" {

resource "google_sql_database_instance" "postgres_sql_instance" {
name = "terrabridge-testing-instance-mysql"
project = var.gcp_project_id
database_version = "POSTGRES_15"
region = "us-central1"
settings {
tier = "db-custom-1-3840"
}
}

resource "google_sql_database" "postgres_database" {
name = "terrabridge-testing-database"
project = var.gcp_project_id
instance = google_sql_database_instance.postgres_sql_instance.name
}

resource "google_sql_user" "postgres_user" {
name = "terrabridge-testing-user"
project = var.gcp_project_id
instance = google_sql_database_instance.postgres_sql_instance.name
password = "terrabridge-testing-password"
}
440 changes: 439 additions & 1 deletion sdks/python/poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions sdks/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ gcsfs = "*"
s3fs = "*"
fsspec = "*"
asyncpg = { version = "^0.29.0", extras = ["dev"] }
boto3-stubs = {extras = ["aws"], version = "^1.34.25"}


[build-system]
Expand Down
Empty file.
Empty file.
10 changes: 4 additions & 6 deletions sdks/python/terrabridge/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ def __init__(
)
self.resource_name = resource_name
resource = get_resource(
resource_name, module_name, state_file or terrabridge.state_file
resource_name,
module_name,
state_file or terrabridge.state_file,
self._terraform_type,
)
if resource["type"] != self._terraform_type:
raise ValueError(
f"Resource {resource_name} is of type {resource['type']}, "
f"but expected {self._terraform_type}."
)
self._attributes = resource["attributes"]
self._dependencies = resource["dependencies"]

Expand Down
21 changes: 14 additions & 7 deletions sdks/python/terrabridge/gcp/cloud_sql.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Optional

from terrabridge.gcp.base import GCPResource
from terrabridge.utils import parse_dependency

try:
from google.cloud.sql.connector import Connector, IPTypes, create_async_connector
Expand Down Expand Up @@ -118,9 +119,12 @@ def __init__(
self.password = self._attributes["password"]
self.cloud_sql_instance: Optional[CloudSQLInstance] = None
for dependency in self._dependencies:
if dependency.startswith(CloudSQLInstance._terraform_type):
dependency = parse_dependency(dependency)
if dependency.resource_type == CloudSQLInstance._terraform_type:
self.cloud_sql_instance = CloudSQLInstance(
dependency.split(".")[1], state_file=state_file
resource_name=dependency.resource_name,
module_name=dependency.module,
state_file=state_file,
)


Expand Down Expand Up @@ -168,9 +172,12 @@ def __init__(
self.name: str = self._attributes["name"]
self.cloud_sql_instance: Optional[CloudSQLInstance] = None
for dependency in self._dependencies:
if dependency.startswith(CloudSQLInstance._terraform_type):
dependency = parse_dependency(dependency)
if dependency.resource_type == CloudSQLInstance._terraform_type:
self.cloud_sql_instance = CloudSQLInstance(
dependency.split(".")[1], state_file=state_file
resource_name=dependency.resource_name,
module_name=dependency.module,
state_file=state_file,
)

def sqlalchemy_engine(
Expand All @@ -181,9 +188,9 @@ def sqlalchemy_engine(
Requires ``terrabridge[gcp]`` and ``sqlalchemy`` to be installed, and whatever
driver is needed for the database version.

* ``POSTGRES``: ``pg8000``
* ``SQLSERVER``: ``pytds``
* ``MYSQL``: ``pymysql``
* ``POSTGRES``: ``pip install pg8000``
* ``SQLSERVER``: ``pip install pytds``
* ``MYSQL``: ``pip install pymysql``

Parameters:
user: The user to connect to the database with.
Expand Down
6 changes: 6 additions & 0 deletions sdks/python/terrabridge/gcp/cloud_sql.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class CloudSQLInstance:
connection_name: str
database_version: str
name: str
project: str
id: str

def __init__(
self,
Expand All @@ -20,6 +22,8 @@ class CloudSQLUser:
name: str
password: str
cloud_sql_instance: Optional[CloudSQLInstance]
project: str
id: str

def __init__(
self,
Expand All @@ -32,6 +36,8 @@ class CloudSQLUser:
class CloudSQLDatabase:
name: str
cloud_sql_instance: Optional[CloudSQLInstance]
project: str
id: str

def __init__(
self,
Expand Down
2 changes: 1 addition & 1 deletion sdks/python/terrabridge/gcp/gcs_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class GCSBucket(GCPResource):

from terrabridge.gcp import GCSBucket

bucket = GCSBucket("queue", state_file="gs://my-bucket/terraform.tfstate")
bucket = GCSBucket("bucket", state_file="gs://my-bucket/terraform.tfstate")
print(bucket.name)

bucket.bucket().upload_from_filename("local_file.txt")
Expand Down
2 changes: 2 additions & 0 deletions sdks/python/terrabridge/gcp/gcs_bucket.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class GCSBucket:
_client: storage.Client
url: str
name: str
project: str
id: str

def __init__(
self,
Expand Down
14 changes: 11 additions & 3 deletions sdks/python/terrabridge/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@
class _ResourceKey:
resource_name: str
module_name: Optional[str]
resource_type: str

def __repr__(self) -> str:
if self.module_name is None:
return self.resource_name
return f"{self.resource_name} in {self.module_name}"


def get_resource(resource_name: str, module_name: Optional[str], tf_state_path: str):
def get_resource(
resource_name: str,
module_name: Optional[str],
tf_state_path: str,
resource_type: str,
):
"""Return the attributes of a resource."""
if tf_state_path not in tf_state_cache:
_parse_terraform_state(tf_state_path)
try:
return tf_state_cache[tf_state_path][_ResourceKey(resource_name, module_name)]
return tf_state_cache[tf_state_path][
_ResourceKey(resource_name, module_name, resource_type)
]
except KeyError:
raise ValueError(
f"Resource {resource_name} not found in {tf_state_path}. "
Expand All @@ -53,7 +61,7 @@ def _parse_terraform_state(tf_state_path: str):
tf_state_cache[tf_state_path] = {}
for resource in tf_state["resources"]:
tf_state_cache[tf_state_path][
_ResourceKey(resource["name"], resource.get("module"))
_ResourceKey(resource["name"], resource.get("module"), resource["type"])
] = {
"attributes": resource["instances"][0].get("attributes", {}),
"dependencies": resource["instances"][0].get("dependencies", {}),
Expand Down
21 changes: 21 additions & 0 deletions sdks/python/terrabridge/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from dataclasses import dataclass
from typing import Optional


@dataclass
class Dependency:
module: Optional[str]
resource_type: str
resource_name: str


def parse_dependency(dependency: str) -> Dependency:
split = dependency.split(".")

module = None
if split[0] == "module":
module = f"{split[0]}.{split[1]}"
split = split[2:]

Check warning on line 18 in sdks/python/terrabridge/utils.py

View check run for this annotation

Codecov / codecov/patch

sdks/python/terrabridge/utils.py#L17-L18

Added lines #L17 - L18 were not covered by tests
resource_type = split[0]
resource_name = split[1]
return Dependency(module, resource_type, resource_name)
7 changes: 4 additions & 3 deletions sdks/python/tests/gcp/bigquery_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

def test_bigquery_dataset():
dataset = BigQueryDataset(
resource_name="dataset", state_file="tests/data/terraform.tfstate"
resource_name="dataset", state_file="tests/data/gcp/terraform.tfstate"
)

assert dataset.project == "terrabridge-testing"
Expand All @@ -15,7 +15,7 @@ def test_bigquery_dataset():

def test_bigquery_table():
table = BigQueryTable(
resource_name="table", state_file="tests/data/terraform.tfstate"
resource_name="table", state_file="tests/data/gcp/terraform.tfstate"
)

assert table.project == "terrabridge-testing"
Expand All @@ -31,7 +31,8 @@ def test_bigquery_table():
def test_type_mismatch():
try:
BigQueryTable(
resource_name="bigtable_table", state_file="tests/data/terraform.tfstate"
resource_name="bigtable_table",
state_file="tests/data/gcp/terraform.tfstate",
)
except ValueError:
return
Expand Down
4 changes: 2 additions & 2 deletions sdks/python/tests/gcp/bigtable_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

def test_bigtable_instance():
instance = BigTableInstance(
resource_name="bigtable_instance", state_file="tests/data/terraform.tfstate"
resource_name="bigtable_instance", state_file="tests/data/gcp/terraform.tfstate"
)

assert instance.project == "terrabridge-testing"
Expand All @@ -15,7 +15,7 @@ def test_bigtable_instance():

def test_bigtable_table():
table = BigTableTable(
resource_name="bigtable_table", state_file="tests/data/terraform.tfstate"
resource_name="bigtable_table", state_file="tests/data/gcp/terraform.tfstate"
)

assert table.project == "terrabridge-testing"
Expand Down
39 changes: 24 additions & 15 deletions sdks/python/tests/gcp/cloud_sql_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

def test_cloud_sql_instance():
instance = CloudSQLInstance(
resource_name="cloud_sql_instance", state_file="tests/data/terraform.tfstate"
resource_name="cloud_sql_instance",
state_file="tests/data/gcp/terraform.tfstate",
)

assert instance.project == "terrabridge-testing"
Expand All @@ -23,7 +24,7 @@ def test_cloud_sql_instance():

def test_cloud_sql_database():
database = CloudSQLDatabase(
resource_name="database", state_file="tests/data/terraform.tfstate"
resource_name="database", state_file="tests/data/gcp/terraform.tfstate"
)

assert database.project == "terrabridge-testing"
Expand All @@ -37,7 +38,9 @@ def test_cloud_sql_database():


def test_cloud_sql_user():
user = CloudSQLUser(resource_name="user", state_file="tests/data/terraform.tfstate")
user = CloudSQLUser(
resource_name="user", state_file="tests/data/gcp/terraform.tfstate"
)

assert user.project == "terrabridge-testing"
assert user.resource_name == "user"
Expand All @@ -52,9 +55,11 @@ def test_cloud_sql_user():

def test_cloud_sql_database_postgres_sqlalchemy():
database = CloudSQLDatabase(
resource_name="database", state_file="tests/data/terraform.tfstate"
resource_name="database", state_file="tests/data/gcp/terraform.tfstate"
)
user = CloudSQLUser(
resource_name="user", state_file="tests/data/gcp/terraform.tfstate"
)
user = CloudSQLUser(resource_name="user", state_file="tests/data/terraform.tfstate")

with patch("terrabridge.gcp.cloud_sql.create_engine") as mock_create_engine:
with patch("terrabridge.gcp.cloud_sql.Connector") as mock_connector:
Expand All @@ -76,10 +81,10 @@ def test_cloud_sql_database_postgres_sqlalchemy():

def test_cloud_sql_database_mysql_sqlalchemy():
database = CloudSQLDatabase(
resource_name="mysql_database", state_file="tests/data/terraform.tfstate"
resource_name="mysql_database", state_file="tests/data/gcp/terraform.tfstate"
)
user = CloudSQLUser(
resource_name="mysql_user1", state_file="tests/data/terraform.tfstate"
resource_name="mysql_user1", state_file="tests/data/gcp/terraform.tfstate"
)

with patch("terrabridge.gcp.cloud_sql.create_engine") as mock_create_engine:
Expand All @@ -100,10 +105,11 @@ def test_cloud_sql_database_mysql_sqlalchemy():

def test_cloud_sql_database_sqlserver_sqlalchemy():
database = CloudSQLDatabase(
resource_name="sql_server_database", state_file="tests/data/terraform.tfstate"
resource_name="sql_server_database",
state_file="tests/data/gcp/terraform.tfstate",
)
user = CloudSQLUser(
resource_name="sql_server_user", state_file="tests/data/terraform.tfstate"
resource_name="sql_server_user", state_file="tests/data/gcp/terraform.tfstate"
)

with patch("terrabridge.gcp.cloud_sql.create_engine") as mock_create_engine:
Expand All @@ -125,9 +131,11 @@ def test_cloud_sql_database_sqlserver_sqlalchemy():
@pytest.mark.asyncio
async def test_cloud_sql_database_postgres_async_sqlalchemy():
database = CloudSQLDatabase(
resource_name="database", state_file="tests/data/terraform.tfstate"
resource_name="database", state_file="tests/data/gcp/terraform.tfstate"
)
user = CloudSQLUser(
resource_name="user", state_file="tests/data/gcp/terraform.tfstate"
)
user = CloudSQLUser(resource_name="user", state_file="tests/data/terraform.tfstate")

with patch("terrabridge.gcp.cloud_sql.create_async_engine") as mock_create_engine:
with patch(
Expand All @@ -153,10 +161,10 @@ async def test_cloud_sql_database_postgres_async_sqlalchemy():
@pytest.mark.asyncio
async def test_cloud_sql_database_mysql_async_sqlalchemy():
database = CloudSQLDatabase(
resource_name="mysql_database", state_file="tests/data/terraform.tfstate"
resource_name="mysql_database", state_file="tests/data/gcp/terraform.tfstate"
)
user = CloudSQLUser(
resource_name="mysql_user1", state_file="tests/data/terraform.tfstate"
resource_name="mysql_user1", state_file="tests/data/gcp/terraform.tfstate"
)

try:
Expand All @@ -169,10 +177,11 @@ async def test_cloud_sql_database_mysql_async_sqlalchemy():
@pytest.mark.asyncio
async def test_cloud_sql_database_sqlserver_async_sqlalchemy():
database = CloudSQLDatabase(
resource_name="sql_server_database", state_file="tests/data/terraform.tfstate"
resource_name="sql_server_database",
state_file="tests/data/gcp/terraform.tfstate",
)
user = CloudSQLUser(
resource_name="sql_server_user", state_file="tests/data/terraform.tfstate"
resource_name="sql_server_user", state_file="tests/data/gcp/terraform.tfstate"
)

try:
Expand Down
2 changes: 1 addition & 1 deletion sdks/python/tests/gcp/cloud_tasks_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

def test_cloud_tasks_queue():
queue = CloudTasksQueue(
resource_name="queue", state_file="tests/data/terraform.tfstate"
resource_name="queue", state_file="tests/data/gcp/terraform.tfstate"
)

assert queue.project == "terrabridge-testing"
Expand Down
Loading
Loading