diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml
index 4420b046..f7d689f6 100644
--- a/.github/workflows/acceptance.yml
+++ b/.github/workflows/acceptance.yml
@@ -22,13 +22,16 @@ jobs:
- name: Docker Compose Up
run: docker compose up --build -d
+ - name: Configure hosts file
+ run: echo "127.0.0.1 materialized frontegg cloud" | sudo tee -a /etc/hosts
+
- name: make testacc
run: make testacc
env:
- MZ_HOST: localhost
- MZ_USER: mz_system
+ MZ_ENDPOINT: http://localhost:3000
+ MZ_CLOUD_ENDPOINT: http://localhost:3001
+ MZ_PASSWORD: mzp_1b2a3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
MZ_SSLMODE: disable
- MZ_PORT: 6877
- name: Docker Compose Down
run: docker compose down
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cff46346..f37eb78b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,48 @@
## Unreleased
+### Features
+* Introduced a unified interface for managing both global and regional resources.
+* Implemented single authentication using an app password for all operations.
+* Added dynamic client allocation for managing different resource types.
+* Enhanced provider configuration with parameters for default settings and optional endpoint overrides.
+* New resources:
+ * App passwords: `materialize_app_password`.
+ * User management `materialize_user`.
+* Added data sources for fetching region details (`materialize_region`).
+* Implemented support for establishing SQL connections across multiple regions.
+* Introduced a new `region` parameter in all resource and data source configurations. This allows users to specify the region for resource creation and data retrieval.
+
+### Breaking Changes
+* **Provider Configuration Changes**:
+ * Deprecated the `host`, `port`, and `user` parameters in the provider configuration. These details are now derived from the app password.
+ * Retained only the `password` definition in the provider configuration. This password is used to fetch all necessary connection information.
+* **New `region` Configuration**:
+ * Introduced a new `default_region` parameter in the provider configuration. This allows users to specify the default region for resource creation.
+ * The `default_region` parameter can be overridden in specific resource configurations if a particular resource needs to be created in a non-default region.
+
+ ```hcl
+ provider "materialize" {
+ password = var.materialize_app_password
+ default_region = "aws/us-east-1"
+ }
+
+ resource "materialize_cluster" "cluster" {
+ name = "cluster"
+ region = "aws/us-west-2"
+ }
+ ```
+
+### Misc
+* Mock Services for Testing:
+ * Added a new mocks directory, which includes mock services for the Cloud API and the FrontEgg API.
+ * These mocks are intended for local testing and CI, facilitating development and testing without the need for a live backend.
+
+### Migration Guide
+* Before upgrading to `v0.5.0`, users should ensure that they have upgraded to `v0.4.x` which introduced the Terraform state migration necessary for `v0.5.0`. After upgrading to `v0.4.x`, users should run `terraform plan` to ensure that the state migration has completed successfully.
+* Users upgrading to `v0.5.0` should update their provider configurations to remove the `host`, `port`, and `user` parameters and ensure that the `password` parameter is set with the app password.
+* For managing resources across multiple regions, users should specify the `default_region` parameter in their provider configuration or override it in specific resource blocks as needed using the `region` parameter.
+
## 0.4.3 - 2024-01-08
### Breaking Changes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3bc91067..fdd6a3b7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -40,15 +40,16 @@ make test
To run the acceptance tests which will simulate running Terraform commands you will need to set the necessary envrionment variables and start the docker compose:
```bash
-export MZ_HOST=localhost
-export MZ_USER=mz_system
-export MZ_SSLMODE=disable
-export MZ_PORT=6877
-
# Start all containers
docker-compose up -d --build
```
+Add the following to your `hosts` file so that the provider can connect to the mock services:
+
+```
+127.0.0.1 materialized frontegg cloud
+```
+
You can then run the acceptance tests:
```bash
@@ -125,6 +126,7 @@ var clusterSchema = map[string]*schema.Schema{
Description: "The size of the cluster.",
Optional: true,
},
+ "region": RegionSchema(),
}
```
@@ -147,8 +149,12 @@ If the resource can be updated we would also have to change the update context `
```go
if d.HasChange("size") {
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
_, newSize := d.GetChange("size")
- b := materialize.NewClusterBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewClusterBuilder(metaDb, o)
if err := b.Resize(newSize.(string)); err != nil {
return diag.FromErr(err)
}
@@ -182,6 +188,10 @@ Schema: map[string]*schema.Schema{
},
},
},
+ "region": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
},
```
@@ -201,7 +211,7 @@ for _, p := range dataSource {
## Cutting a release
-To cut a new release of the provider, create a new tag and push that tag. This will trigger a Github Action to generate the artifacts necessary for the Terraform Registry.
+To cut a new release of the provider, create a new tag and push that tag. This will trigger a GitHub Action to generate the artifacts necessary for the Terraform Registry.
```bash
git tag -a vX.Y.Z -m vX.Y.Z
diff --git a/docker-compose.yml b/docker-compose.yml
index d058122c..00caf4e4 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -87,3 +87,15 @@ services:
TF_LOG: INFO
command: >
sh -c "tail -F /dev/null"
+
+ frontegg:
+ container_name: frontegg
+ build: mocks/frontegg
+ ports:
+ - "3000:3000"
+
+ cloud:
+ container_name: cloud
+ build: mocks/cloud
+ ports:
+ - "3001:3001"
diff --git a/docs/data-sources/cluster.md b/docs/data-sources/cluster.md
index 2803827c..193a6d73 100644
--- a/docs/data-sources/cluster.md
+++ b/docs/data-sources/cluster.md
@@ -23,6 +23,7 @@ data "materialize_cluster" "all" {}
- `clusters` (List of Object) The clusters in the account (see [below for nested schema](#nestedatt--clusters))
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
### Nested Schema for `clusters`
diff --git a/docs/data-sources/cluster_replica.md b/docs/data-sources/cluster_replica.md
index ee6f1972..937270f0 100644
--- a/docs/data-sources/cluster_replica.md
+++ b/docs/data-sources/cluster_replica.md
@@ -23,6 +23,7 @@ data "materialize_cluster_replica" "all" {}
- `cluster_replicas` (List of Object) The cluster replicas in the account (see [below for nested schema](#nestedatt--cluster_replicas))
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
### Nested Schema for `cluster_replicas`
diff --git a/docs/data-sources/connection.md b/docs/data-sources/connection.md
index d56bd3f7..5c19d5d3 100644
--- a/docs/data-sources/connection.md
+++ b/docs/data-sources/connection.md
@@ -37,6 +37,7 @@ data "materialize_connection" "materialize_schema" {
- `connections` (List of Object) The connections in the account (see [below for nested schema](#nestedatt--connections))
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
### Nested Schema for `connections`
diff --git a/docs/data-sources/current_cluster.md b/docs/data-sources/current_cluster.md
index d0222e30..1cfc57fb 100644
--- a/docs/data-sources/current_cluster.md
+++ b/docs/data-sources/current_cluster.md
@@ -27,3 +27,4 @@ output "cluster_name" {
- `id` (String) The ID of this resource.
- `name` (String)
+- `region` (String) The region in which the resource is located.
diff --git a/docs/data-sources/current_database.md b/docs/data-sources/current_database.md
index 8da234be..1f91792b 100644
--- a/docs/data-sources/current_database.md
+++ b/docs/data-sources/current_database.md
@@ -27,3 +27,4 @@ output "database_name" {
- `id` (String) The ID of this resource.
- `name` (String)
+- `region` (String) The region in which the resource is located.
diff --git a/docs/data-sources/database.md b/docs/data-sources/database.md
index 2b39cda2..d3e18a32 100644
--- a/docs/data-sources/database.md
+++ b/docs/data-sources/database.md
@@ -23,6 +23,7 @@ data "materialize_database" "all" {}
- `databases` (List of Object) The databases in the account (see [below for nested schema](#nestedatt--databases))
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
### Nested Schema for `databases`
diff --git a/docs/data-sources/egress_ips.md b/docs/data-sources/egress_ips.md
index 697df62f..d0247fbd 100644
--- a/docs/data-sources/egress_ips.md
+++ b/docs/data-sources/egress_ips.md
@@ -27,3 +27,4 @@ output "ips" {
- `egress_ips` (List of String) The egress IPs in the account
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
diff --git a/docs/data-sources/index.md b/docs/data-sources/index.md
index cfe141cc..ae1041bf 100644
--- a/docs/data-sources/index.md
+++ b/docs/data-sources/index.md
@@ -37,6 +37,7 @@ data "materialize_index" "materialize_schema" {
- `id` (String) The ID of this resource.
- `indexes` (List of Object) The indexes in the account (see [below for nested schema](#nestedatt--indexes))
+- `region` (String) The region in which the resource is located.
### Nested Schema for `indexes`
diff --git a/docs/data-sources/materialized_view.md b/docs/data-sources/materialized_view.md
index b7b988b6..72a8357c 100644
--- a/docs/data-sources/materialized_view.md
+++ b/docs/data-sources/materialized_view.md
@@ -37,6 +37,7 @@ data "materialize_materialized_view" "materialize_schema" {
- `id` (String) The ID of this resource.
- `materialized_views` (List of Object) The materialized views in the account (see [below for nested schema](#nestedatt--materialized_views))
+- `region` (String) The region in which the resource is located.
### Nested Schema for `materialized_views`
diff --git a/docs/data-sources/region.md b/docs/data-sources/region.md
new file mode 100644
index 00000000..21a8a9da
--- /dev/null
+++ b/docs/data-sources/region.md
@@ -0,0 +1,40 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "materialize_region Data Source - terraform-provider-materialize"
+subcategory: ""
+description: |-
+
+---
+
+# materialize_region (Data Source)
+
+
+
+## Example Usage
+
+```terraform
+data "materialize_region" "all" {}
+
+output "region" {
+ value = data.materialize_region.all
+}
+```
+
+
+## Schema
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `regions` (List of Object) (see [below for nested schema](#nestedatt--regions))
+
+
+### Nested Schema for `regions`
+
+Read-Only:
+
+- `cloud_provider` (String)
+- `host` (String)
+- `id` (String)
+- `name` (String)
+- `url` (String)
diff --git a/docs/data-sources/role.md b/docs/data-sources/role.md
index 13f8d69f..93171c43 100644
--- a/docs/data-sources/role.md
+++ b/docs/data-sources/role.md
@@ -22,6 +22,7 @@ data "materialize_role" "all" {}
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `roles` (List of Object) The roles in the account (see [below for nested schema](#nestedatt--roles))
diff --git a/docs/data-sources/schema.md b/docs/data-sources/schema.md
index 979c4552..20cfe09d 100644
--- a/docs/data-sources/schema.md
+++ b/docs/data-sources/schema.md
@@ -30,6 +30,7 @@ data "materialize_schema" "materialize" {
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `schemas` (List of Object) The schemas in the account (see [below for nested schema](#nestedatt--schemas))
diff --git a/docs/data-sources/secret.md b/docs/data-sources/secret.md
index b3781e43..721d8d93 100644
--- a/docs/data-sources/secret.md
+++ b/docs/data-sources/secret.md
@@ -36,6 +36,7 @@ data "materialize_secret" "materialize_schema" {
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `secrets` (List of Object) The secrets in the account (see [below for nested schema](#nestedatt--secrets))
diff --git a/docs/data-sources/sink.md b/docs/data-sources/sink.md
index 13afded1..183bf8f1 100644
--- a/docs/data-sources/sink.md
+++ b/docs/data-sources/sink.md
@@ -36,6 +36,7 @@ data "materialize_sink" "materialize_schema" {
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `sinks` (List of Object) The sinks in the account (see [below for nested schema](#nestedatt--sinks))
diff --git a/docs/data-sources/source.md b/docs/data-sources/source.md
index 177ea98e..5fe1ea81 100644
--- a/docs/data-sources/source.md
+++ b/docs/data-sources/source.md
@@ -36,6 +36,7 @@ data "materialize_source" "materialize_schema" {
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `sources` (List of Object) The sources in the account (see [below for nested schema](#nestedatt--sources))
diff --git a/docs/data-sources/table.md b/docs/data-sources/table.md
index 09da5ecc..0fc25c21 100644
--- a/docs/data-sources/table.md
+++ b/docs/data-sources/table.md
@@ -23,6 +23,7 @@ description: |-
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `tables` (List of Object) The tables in the account (see [below for nested schema](#nestedatt--tables))
diff --git a/docs/data-sources/type.md b/docs/data-sources/type.md
index 1c907389..e33c03b9 100644
--- a/docs/data-sources/type.md
+++ b/docs/data-sources/type.md
@@ -23,6 +23,7 @@ description: |-
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `types` (List of Object) The types in the account (see [below for nested schema](#nestedatt--types))
diff --git a/docs/data-sources/view.md b/docs/data-sources/view.md
index 50c08774..ebfce43f 100644
--- a/docs/data-sources/view.md
+++ b/docs/data-sources/view.md
@@ -36,6 +36,7 @@ data "materialize_view" "materialize_schema" {
### Read-Only
- `id` (String) The ID of this resource.
+- `region` (String) The region in which the resource is located.
- `views` (List of Object) The views in the account (see [below for nested schema](#nestedatt--views))
diff --git a/docs/developer/design-v2-2023-11-11.md b/docs/developer/design-v2-2023-11-11.md
new file mode 100644
index 00000000..58783e30
--- /dev/null
+++ b/docs/developer/design-v2-2023-11-11.md
@@ -0,0 +1,199 @@
+# Design Document for Materialize Terraform Provider
+
+The proposed updates to the Materialize Terraform provider aim to streamline the management of resources within Materialize, offering a unified interface for global and regional resources. The provider will leverage a single authentication method, an app password, to derive the necessary configurations for seamless interaction with various services. It will also incorporate a dynamic client allocation mechanism to handle different resource types and their requirements.
+
+## Provider Overview
+
+### Objectives
+
+- To provide a singular Terraform provider capable of interfacing with multiple backends and services.
+- To facilitate the management of global resources and regional deployments through a consistent workflow.
+- To enable a high degree of automation in resource provisioning and management, thereby reducing manual overhead and potential for errors.
+
+### Features
+
+- **Single Authentication**: Utilizing an app password to access and manage resources without the need for multiple credentials.
+- **Global and Regional Resource Management**: Allowing users to manage resources that are not bound by regional constraints, as well as those that are region-specific.
+- **Dynamic Client Allocation**: Depending on the resource's requirement, the appropriate client (DB, Frontegg, Cloud API and etc.) will be allocated dynamically.
+
+## Architecture
+
+### Provider Configuration
+
+The provider will be initialized with parameters that determine its behavior and default settings:
+
+```hcl
+provider "materialize" {
+ app_password = var.materialize_app_password
+ default_region = var.materialize_default_region
+}
+```
+
+Users will specify the app password and the default region for operations. Optionally, the endpoint can be overridden for testing or staging purposes by defining a `MZ_ENDPOINT` environment variable or "endpoint" parameter in the provider configuration block.
+
+The `MZ_ENDPOINT` environment variable will be hidden from the provider's documentation and will be used only for testing and development purposes.
+
+### Multi-Client Structure
+
+The provider will maintain a map of clients for database operations across different regions and a client for interfacing with the Frontegg API.
+
+```hcl
+type ProviderMeta struct {
+ DB map[Region]*clients.DBClient
+ Frontegg *clients.FronteggClient
+ // Future: CloudAPI *clients.CloudAPIClient
+}
+```
+
+This structure allows for scalability and extension of the provider to incorporate additional clients as necessary.
+
+## Resources and Operations
+
+### Region Resource
+
+Responsible for managing the availability of Materialize regions. It will interact with the Cloud API to enable or retrieve regions as requested by the user.
+
+```hcl
+resource "materialize_region" "aws_us_east_1" {
+ region = "aws/us-east-1"
+}
+```
+
+Operations:
+
+- **Enable Region**: Uses the Cloud API to enable a new region.
+- **Read Region**: Retrieves the status of a region from the Cloud API.
+- **Disable Region**: Noop. Regions cannot be disabled once enabled.
+
+### User Resource
+
+Manages the lifecycle of a user within the Frontegg platform.
+
+```hcl
+resource "materialize_user" "example_user" {
+ email = "user@example.com"
+ auth_provider = "local"
+ organization_roles = ["admin", "member"]
+ # Additional attributes...
+}
+```
+
+Operations:
+
+- **Create User**: Invokes the Frontegg API to create/invite a user.
+- **Read User**: Retrieves user details from Frontegg.
+- **Update User**: Attaches or detaches roles from the user.
+- **Delete User**: Removes the user from Frontegg.
+
+### Organization Data Source?
+
+Gets the associated organization for the provided app password.
+
+```hcl
+data "materialize_app_organization" "current" {}
+```
+
+Operations:
+
+- **List Organizations**: Fetches all available organizations from Frontegg.
+
+### Role Data Source
+
+Generates a list of available roles from Frontegg.
+
+```hcl
+data "materialize_organization_roles" "all" {}
+```
+
+Operations:
+
+- **List Roles**: Fetches all available roles from Frontegg.
+
+## Testing Strategy
+
+Along the existing unit tests described in the [design document](../../DESIGN.md), the provider will include a comprehensive suite of tests for all resources and operations, including:
+
+- **Unit Tests**: Will run against a test Materialize environment or a mock service to ensure that the provider functions correctly in isolation.
+- **Integration Tests**: Will run against staging instance to confirm that the provider interacts correctly with the actual services.
+- **Acceptance Tests**: То be determined.
+
+## State Management
+
+The provider will ensure that the Terraform state reflects the true state of resources in Materialize Cloud and Frontegg, using Terraform's state management capabilities.
+
+## User Experience and Documentation
+
+Users should be able to easily upgrade to the new provider version without having to make significant changes to their existing configurations.
+
+The release should include clear documentation and examples to help users understand the new features and how to use them.
+
+This should be clearly communicated to users through release notes and other channels.
+
+Clear and detailed documentation will accompany the provider, explaining usage, resource configuration, and troubleshooting.
+
+### Edge Case Management
+
+Further exploration of how the provider will handle edge cases, such as delays in region enablement or Frontegg API failures, will be included in the design document.
+
+## Database Resource
+
+### Integration with Frontegg and Global API
+
+The Materialize Terraform provider will integrate with the Frontegg API to dynamically fetch the necessary credentials and regional endpoint information.
+
+This approach streamlines the process of establishing SQL connections across various Materialize regions using a single app password.
+
+### Resource Definitions
+
+#### Cluster in an Existing Region
+
+To create a cluster in a region that has been previously enabled, users can define a `materialize_cluster` resource without creating a dependency on the region's resource within Terraform. This is useful when operating in regions activated outside the scope of the current Terraform configuration.
+
+```hcl
+resource "materialize_cluster" "eu_west_1_cluster" {
+ region = "aws/eu-west-1"
+ # Additional configuration options...
+}
+```
+
+#### Cluster in the Default Provider Region
+
+For convenience, users can create clusters without specifying a region, in which case the provider uses the default region specified in the provider's configuration block. This simplifies resource definitions and maintains consistency across Terraform configurations.
+
+```hcl
+resource "materialize_cluster" "default_region_cluster" {
+ # The provider will infer the region from the default settings.
+ # Additional configuration options...
+}
+```
+
+#### Cluster in a Terraform-Enabled Region
+
+When a region is enabled within Terraform, resource definitions can reference the `materialize_region` resource. This ensures that Terraform manages dependencies correctly, creating the cluster only after the region is fully enabled.
+
+```hcl
+resource "materialize_cluster" "us_east_1_cluster" {
+ region = materialize_region.aws_us_east_1.region
+ # Additional configuration options...
+}
+```
+
+### Enhanced Workflow
+
+The provider will handle the following workflow:
+
+1. **Authentication**: Utilize the app password to retrieve the username associated with the provided token.
+2. **Regional Endpoint Retrieval**: Query the global API to obtain the hostname and port for the specified region.
+3. **SQL Connection Establishment**: Connect to the desired region's SQL interface using the retrieved credentials and endpoint information.
+4. **Resource Management**: Facilitate the creation, updating, and deletion of resources within the connected region using the established SQL connection.
+
+### Error Handling and Region Validation
+
+The provider will have error handling to provide clear and actionable feedback when:
+
+- A specified region is not enabled or in the process of being disabled.
+- There are network or authentication issues while establishing the SQL connection.
+
+### Simplifying Configuration
+
+By abstracting away the complexities of managing credentials and endpoints, the provider allows users to focus on the high-level definitions of their Materialize infrastructure, promoting a simplified and more efficient configuration process.
diff --git a/docs/index.md b/docs/index.md
index d77ded7c..23a6e8ce 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -14,21 +14,16 @@ Configure the provider by adding the following block to your Terraform project:
```terraform
# Configuration-based authentication
provider "materialize" {
- host = var.materialize_host # optionally use MZ_HOST env var
- user = var.materialize_user # optionally use MZ_USER env var
- password = var.materialize_password # optionally use MZ_PASSWORD env var
- port = var.materialize_port # optionally use MZ_PORT env var
- database = var.materialize_database # optionally use MZ_DATABASE env var
+ password = var.materialize_password # optionally use MZ_PASSWORD env var
+ default_region = "aws/us-east-1" # optionally use MZ_REGION env var
}
```
## Schema
-* `host` (String) Materialize host. Can also come from the `MZ_HOST` environment variable.
-* `user` (String) Materialize user. Can also come from the `MZ_USER` environment variable.
-* `password` (String, Sensitive) Materialize host. Can also come from the `MZ_PASSWORD` environment variable.
-* `port` (Number) The Materialize port number to connect to at the server host. Can also come from the `MZ_PORT` environment variable. Defaults to 6875.
-* `database` (String) The Materialize database. Can also come from the `MZ_DATABASE` environment variable. Defaults to `materialize`.
+* `password` (String, Sensitive) Materialize App Password. Can also come from the `MZ_PASSWORD` environment variable.
+* `database` (String, Optional) The Materialize database. Can also come from the `MZ_DATABASE` environment variable. Defaults to `materialize`.
+* `default_region` (String, Optional) The Materialize AWS region. Can also come from the `MZ_DEFAULT_REGION` environment variable. Defaults to `aws/us-east-1`.
## Order precedence
diff --git a/docs/resources/app_password.md b/docs/resources/app_password.md
new file mode 100644
index 00000000..3c34b80d
--- /dev/null
+++ b/docs/resources/app_password.md
@@ -0,0 +1,43 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "materialize_app_password Resource - terraform-provider-materialize"
+subcategory: ""
+description: |-
+
+---
+
+# materialize_app_password (Resource)
+
+
+
+## Example Usage
+
+```terraform
+resource "materialize_app_password" "example_app_password" {
+ name = "example_app_password_name"
+}
+```
+
+
+## Schema
+
+### Required
+
+- `name` (String)
+
+### Read-Only
+
+- `created_at` (String)
+- `id` (String) The ID of this resource.
+- `owner` (String)
+- `password` (String, Sensitive)
+- `secret` (String, Sensitive)
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# App passwords can be imported using the app password id:
+terraform import materialize_app_password.example_app_password
+```
diff --git a/docs/resources/cluster.md b/docs/resources/cluster.md
index c19662a2..7f09fa1f 100644
--- a/docs/resources/cluster.md
+++ b/docs/resources/cluster.md
@@ -33,6 +33,7 @@ resource "materialize_cluster" "example_cluster" {
- `introspection_debugging` (Boolean) Whether to introspect the gathering of the introspection data.
- `introspection_interval` (String) The interval at which to collect introspection data.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `replication_factor` (Number) The number of replicas of each dataflow-powered object to maintain.
- `size` (String) The size of the managed cluster.
diff --git a/docs/resources/cluster_grant.md b/docs/resources/cluster_grant.md
index 4a85ecd2..30f3b1ef 100644
--- a/docs/resources/cluster_grant.md
+++ b/docs/resources/cluster_grant.md
@@ -30,6 +30,10 @@ resource "materialize_cluster_grant" "cluster_grant_usage" {
- `privilege` (String) The privilege to grant to the object.
- `role_name` (String) The name of the role to grant privilege to.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/cluster_grant_default_privilege.md b/docs/resources/cluster_grant_default_privilege.md
index de988c2f..14852f60 100644
--- a/docs/resources/cluster_grant_default_privilege.md
+++ b/docs/resources/cluster_grant_default_privilege.md
@@ -30,6 +30,10 @@ resource "materialize_cluster_grant_default_privilege" "example" {
- `privilege` (String) The privilege to grant to the object.
- `target_role_name` (String) The default privilege will apply to objects created by this role. If this is left blank, then the current role is assumed. Use the `PUBLIC` pseudo-role to target objects created by all roles.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/cluster_replica b/docs/resources/cluster_replica
index 23b759ef..8cbb5871 100644
--- a/docs/resources/cluster_replica
+++ b/docs/resources/cluster_replica
@@ -39,6 +39,7 @@ resource "materialize_cluster_replica" "example_cluster_replica" {
- `idle_arrangement_merge_effort` (Number) The amount of effort to exert compacting arrangements during idle periods. This is an unstable option! It may be changed or removed at any time.
- `introspection_debugging` (Boolean) Whether to introspect the gathering of the introspection data.
- `introspection_interval` (String) The interval at which to collect introspection data.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
## Import
diff --git a/docs/resources/cluster_replica.md b/docs/resources/cluster_replica.md
index d0d35da8..7e45bf00 100644
--- a/docs/resources/cluster_replica.md
+++ b/docs/resources/cluster_replica.md
@@ -37,6 +37,7 @@ resource "materialize_cluster_replica" "example_cluster_replica" {
- `idle_arrangement_merge_effort` (Number) The amount of effort to exert compacting arrangements during idle periods. This is an unstable option! It may be changed or removed at any time.
- `introspection_debugging` (Boolean) Whether to introspect the gathering of the introspection data.
- `introspection_interval` (String) The interval at which to collect introspection data.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
### Read-Only
diff --git a/docs/resources/connection_aws_privatelink.md b/docs/resources/connection_aws_privatelink.md
index 9cc8d165..5bde1296 100644
--- a/docs/resources/connection_aws_privatelink.md
+++ b/docs/resources/connection_aws_privatelink.md
@@ -43,6 +43,7 @@ resource "materialize_connection_aws_privatelink" "example_privatelink_connectio
- `comment` (String) **Private Preview** Comment on an object in the database.
- `database_name` (String) The identifier for the connection database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the connection schema. Defaults to `public`.
### Read-Only
diff --git a/docs/resources/connection_confluent_schema_registry.md b/docs/resources/connection_confluent_schema_registry.md
index b33949e4..28517511 100644
--- a/docs/resources/connection_confluent_schema_registry.md
+++ b/docs/resources/connection_confluent_schema_registry.md
@@ -49,6 +49,7 @@ resource "materialize_connection_confluent_schema_registry" "example_confluent_s
- `database_name` (String) The identifier for the connection database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
- `password` (Block List, Max: 1) The password for the Confluent Schema Registry. (see [below for nested schema](#nestedblock--password))
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the connection schema. Defaults to `public`.
- `ssh_tunnel` (Block List, Max: 1) The SSH tunnel configuration for the Confluent Schema Registry. (see [below for nested schema](#nestedblock--ssh_tunnel))
- `ssl_certificate` (Block List, Max: 1) The client certificate for the Confluent Schema Registry.. Can be supplied as either free text using `text` or reference to a secret object using `secret`. (see [below for nested schema](#nestedblock--ssl_certificate))
diff --git a/docs/resources/connection_grant.md b/docs/resources/connection_grant.md
index bf945f7e..c960b5a5 100644
--- a/docs/resources/connection_grant.md
+++ b/docs/resources/connection_grant.md
@@ -34,6 +34,10 @@ resource "materialize_connection_grant" "connection_grant_usage" {
- `role_name` (String) The name of the role to grant privilege to.
- `schema_name` (String) The schema that the connection being to.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/connection_grant_default_privilege.md b/docs/resources/connection_grant_default_privilege.md
index 3d46adf1..bdf0b921 100644
--- a/docs/resources/connection_grant_default_privilege.md
+++ b/docs/resources/connection_grant_default_privilege.md
@@ -35,6 +35,7 @@ resource "materialize_connection_grant_default_privilege" "example" {
### Optional
- `database_name` (String) The default privilege will apply only to objects created in this database, if specified.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The default privilege will apply only to objects created in this schema, if specified.
### Read-Only
diff --git a/docs/resources/connection_kafka.md b/docs/resources/connection_kafka.md
index 3443642d..c0aa39d5 100644
--- a/docs/resources/connection_kafka.md
+++ b/docs/resources/connection_kafka.md
@@ -85,6 +85,7 @@ resource "materialize_connection_kafka" "example_kafka_connection_multiple_broke
- `database_name` (String) The identifier for the connection database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
- `progress_topic` (String) The name of a topic that Kafka sinks can use to track internal consistency metadata.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `sasl_mechanisms` (String) The SASL mechanism for the Kafka broker.
- `sasl_password` (Block List, Max: 1) The SASL password for the Kafka broker. (see [below for nested schema](#nestedblock--sasl_password))
- `sasl_username` (Block List, Max: 1) The SASL username for the Kafka broker.. Can be supplied as either free text using `text` or reference to a secret object using `secret`. (see [below for nested schema](#nestedblock--sasl_username))
diff --git a/docs/resources/connection_postgres.md b/docs/resources/connection_postgres.md
index ad8f0ed3..a33e5f6b 100644
--- a/docs/resources/connection_postgres.md
+++ b/docs/resources/connection_postgres.md
@@ -90,6 +90,7 @@ resource "materialize_connection_postgres" "example_postgres_connection" {
- `ownership_role` (String) The owernship role of the object.
- `password` (Block List, Max: 1) The Postgres database password. (see [below for nested schema](#nestedblock--password))
- `port` (Number) The Postgres database port.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the connection schema. Defaults to `public`.
- `ssh_tunnel` (Block List, Max: 1) The SSH tunnel configuration for the Postgres database. (see [below for nested schema](#nestedblock--ssh_tunnel))
- `ssl_certificate` (Block List, Max: 1) The client certificate for the Postgres database.. Can be supplied as either free text using `text` or reference to a secret object using `secret`. (see [below for nested schema](#nestedblock--ssl_certificate))
diff --git a/docs/resources/connection_ssh_tunnel.md b/docs/resources/connection_ssh_tunnel.md
index 959e81b9..38ec9942 100644
--- a/docs/resources/connection_ssh_tunnel.md
+++ b/docs/resources/connection_ssh_tunnel.md
@@ -44,6 +44,7 @@ resource "materialize_connection_ssh_tunnel" "example_ssh_connection" {
- `comment` (String) **Private Preview** Comment on an object in the database.
- `database_name` (String) The identifier for the connection database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the connection schema. Defaults to `public`.
### Read-Only
diff --git a/docs/resources/database.md b/docs/resources/database.md
index 520bdfbf..a1504399 100644
--- a/docs/resources/database.md
+++ b/docs/resources/database.md
@@ -29,6 +29,7 @@ resource "materialize_database" "example_database" {
- `comment` (String) **Private Preview** Comment on an object in the database.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
### Read-Only
diff --git a/docs/resources/database_grant.md b/docs/resources/database_grant.md
index b6beb3f1..a10ed659 100644
--- a/docs/resources/database_grant.md
+++ b/docs/resources/database_grant.md
@@ -30,6 +30,10 @@ resource "materialize_database_grant" "database_grant_usage" {
- `privilege` (String) The privilege to grant to the object.
- `role_name` (String) The name of the role to grant privilege to.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/database_grant_default_privilege.md b/docs/resources/database_grant_default_privilege.md
index 29a1814c..43d6d032 100644
--- a/docs/resources/database_grant_default_privilege.md
+++ b/docs/resources/database_grant_default_privilege.md
@@ -30,6 +30,10 @@ resource "materialize_database_grant_default_privilege" "example" {
- `privilege` (String) The privilege to grant to the object.
- `target_role_name` (String) The default privilege will apply to objects created by this role. If this is left blank, then the current role is assumed. Use the `PUBLIC` pseudo-role to target objects created by all roles.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/grant_system_privilege.md b/docs/resources/grant_system_privilege.md
index f6ab0ea7..397920bd 100644
--- a/docs/resources/grant_system_privilege.md
+++ b/docs/resources/grant_system_privilege.md
@@ -28,6 +28,10 @@ resource "materialize_grant_system_privilege" "role_createdb" {
- `privilege` (String) The system privilege to grant.
- `role_name` (String) The name of the role to grant privilege to.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/index.md b/docs/resources/index.md
index a2819a58..653772f9 100644
--- a/docs/resources/index.md
+++ b/docs/resources/index.md
@@ -46,6 +46,7 @@ resource "materialize_index" "loadgen_index" {
- `default` (Boolean) Creates a default index using all inferred columns are used.
- `method` (String) The name of the index method to use.
- `name` (String) The identifier for the index.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
### Read-Only
diff --git a/docs/resources/materialized_view.md b/docs/resources/materialized_view.md
index 73139b93..a90f628b 100644
--- a/docs/resources/materialized_view.md
+++ b/docs/resources/materialized_view.md
@@ -52,6 +52,7 @@ resource "materialize_materialized_view" "simple_materialized_view" {
- `database_name` (String) The identifier for the materialized view database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `not_null_assertion` (List of String) **Private Preview** A list of columns for which to create non-null assertions.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the materialized view schema. Defaults to `public`.
### Read-Only
diff --git a/docs/resources/materialized_view_grant.md b/docs/resources/materialized_view_grant.md
index 8ea1daf2..84e118a0 100644
--- a/docs/resources/materialized_view_grant.md
+++ b/docs/resources/materialized_view_grant.md
@@ -34,6 +34,10 @@ resource "materialize_materialized_view_grant" "materialized_view_grant_select"
- `role_name` (String) The name of the role to grant privilege to.
- `schema_name` (String) The schema that the materialized view being to.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/role.md b/docs/resources/role.md
index b46d62dc..10e80913 100644
--- a/docs/resources/role.md
+++ b/docs/resources/role.md
@@ -28,6 +28,7 @@ resource "materialize_role" "example_role" {
### Optional
- `comment` (String) **Private Preview** Comment on an object in the database.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
### Read-Only
diff --git a/docs/resources/role_grant.md b/docs/resources/role_grant.md
index 7996ddd9..61bfdbd8 100644
--- a/docs/resources/role_grant.md
+++ b/docs/resources/role_grant.md
@@ -28,6 +28,10 @@ resource "materialize_role_grant" "role_grant_user" {
- `member_name` (String) The role name to add to role_name as a member.
- `role_name` (String) The role name to add member_name as a member.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/schema.md b/docs/resources/schema.md
index 7d0a8ef2..9c126913 100644
--- a/docs/resources/schema.md
+++ b/docs/resources/schema.md
@@ -31,6 +31,7 @@ resource "materialize_schema" "example_schema" {
- `comment` (String) **Private Preview** Comment on an object in the database.
- `database_name` (String) The identifier for the schema database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
### Read-Only
diff --git a/docs/resources/schema_grant.md b/docs/resources/schema_grant.md
index 5085f617..8f5b0c1c 100644
--- a/docs/resources/schema_grant.md
+++ b/docs/resources/schema_grant.md
@@ -32,6 +32,10 @@ resource "materialize_schema_grant" "schema_grant_usage" {
- `role_name` (String) The name of the role to grant privilege to.
- `schema_name` (String) The schema that is being granted on.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/schema_grant_default_privilege.md b/docs/resources/schema_grant_default_privilege.md
index 01633e41..0a197366 100644
--- a/docs/resources/schema_grant_default_privilege.md
+++ b/docs/resources/schema_grant_default_privilege.md
@@ -34,6 +34,7 @@ resource "materialize_schema_grant_default_privilege" "example" {
### Optional
- `database_name` (String) The default privilege will apply only to objects created in this database, if specified.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
### Read-Only
diff --git a/docs/resources/secret.md b/docs/resources/secret.md
index 37584fb2..05b8543a 100644
--- a/docs/resources/secret.md
+++ b/docs/resources/secret.md
@@ -32,6 +32,7 @@ resource "materialize_secret" "example_secret" {
- `comment` (String) **Private Preview** Comment on an object in the database.
- `database_name` (String) The identifier for the secret database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the secret schema. Defaults to `public`.
### Read-Only
diff --git a/docs/resources/secret_grant.md b/docs/resources/secret_grant.md
index 69e39fb0..9ee9abbb 100644
--- a/docs/resources/secret_grant.md
+++ b/docs/resources/secret_grant.md
@@ -34,6 +34,10 @@ resource "materialize_secret_grant" "secret_grant_usage" {
- `schema_name` (String) The schema that the secret being to.
- `secret_name` (String) The secret that is being granted on.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/secret_grant_default_privilege.md b/docs/resources/secret_grant_default_privilege.md
index d7153f32..a35cf79b 100644
--- a/docs/resources/secret_grant_default_privilege.md
+++ b/docs/resources/secret_grant_default_privilege.md
@@ -35,6 +35,7 @@ resource "materialize_secret_grant_default_privilege" "example" {
### Optional
- `database_name` (String) The default privilege will apply only to objects created in this database, if specified.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The default privilege will apply only to objects created in this schema, if specified.
### Read-Only
diff --git a/docs/resources/sink_kafka.md b/docs/resources/sink_kafka.md
index 72c7f0fe..350d93b4 100644
--- a/docs/resources/sink_kafka.md
+++ b/docs/resources/sink_kafka.md
@@ -67,6 +67,7 @@ resource "materialize_sink_kafka" "example_sink_kafka" {
- `key` (List of String) An optional list of columns to use for the Kafka key. If unspecified, the Kafka key is left unset.
- `key_not_enforced` (Boolean) Disable Materialize's validation of the key's uniqueness.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the sink schema. Defaults to `public`.
- `size` (String) The size of the sink. If not specified, the `cluster_name` option must be specified.
- `snapshot` (Boolean) Whether to emit the consolidated results of the query before the sink was created at the start of the sink.
diff --git a/docs/resources/source_grant.md b/docs/resources/source_grant.md
index 250c8346..b34ec884 100644
--- a/docs/resources/source_grant.md
+++ b/docs/resources/source_grant.md
@@ -34,6 +34,10 @@ resource "materialize_source_grant" "source_grant_select" {
- `schema_name` (String) The schema that the view being to.
- `source_name` (String) The source that is being granted on.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/source_kafka.md b/docs/resources/source_kafka.md
index 04e821f3..f6b1abac 100644
--- a/docs/resources/source_kafka.md
+++ b/docs/resources/source_kafka.md
@@ -72,6 +72,7 @@ resource "materialize_source_kafka" "example_source_kafka" {
- `include_timestamp_alias` (String) Provide an alias for the timestamp column.
- `key_format` (Block List, Max: 1) Set the key format explicitly. (see [below for nested schema](#nestedblock--key_format))
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the source schema. Defaults to `public`.
- `size` (String) The size of the source. If not specified, the `cluster_name` option must be specified.
- `start_offset` (List of Number) Read partitions from the specified offset.
diff --git a/docs/resources/source_load_generator.md b/docs/resources/source_load_generator.md
index 68063895..6c41ec68 100644
--- a/docs/resources/source_load_generator.md
+++ b/docs/resources/source_load_generator.md
@@ -50,6 +50,7 @@ resource "materialize_source_load_generator" "example_source_load_generator" {
- `expose_progress` (Block List, Max: 1) The name of the progress subsource for the source. If this is not specified, the subsource will be named `_progress`. (see [below for nested schema](#nestedblock--expose_progress))
- `marketing_options` (Block List, Max: 1) Marketing Options. (see [below for nested schema](#nestedblock--marketing_options))
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the source schema. Defaults to `public`.
- `size` (String) The size of the source. If not specified, the `cluster_name` option must be specified.
- `tpch_options` (Block List, Max: 1) TPCH Options. (see [below for nested schema](#nestedblock--tpch_options))
diff --git a/docs/resources/source_postgres.md b/docs/resources/source_postgres.md
index e9a4c75f..290bbff9 100644
--- a/docs/resources/source_postgres.md
+++ b/docs/resources/source_postgres.md
@@ -59,6 +59,7 @@ resource "materialize_source_postgres" "example_source_postgres" {
- `database_name` (String) The identifier for the source database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `expose_progress` (Block List, Max: 1) The name of the progress subsource for the source. If this is not specified, the subsource will be named `_progress`. (see [below for nested schema](#nestedblock--expose_progress))
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema` (List of String) Creates subsources for specific schemas. If neither table or schema is specified, will default to ALL TABLES
- `schema_name` (String) The identifier for the source schema. Defaults to `public`.
- `size` (String) The size of the source. If not specified, the `cluster_name` option must be specified.
diff --git a/docs/resources/source_webhook.md b/docs/resources/source_webhook.md
index 45933c77..2d681d94 100644
--- a/docs/resources/source_webhook.md
+++ b/docs/resources/source_webhook.md
@@ -67,6 +67,7 @@ resource "materialize_source_webhook" "example_webhook" {
- `include_header` (Block List) Map a header value from a request into a column. (see [below for nested schema](#nestedblock--include_header))
- `include_headers` (Block List, Max: 1) Include headers in the webhook. (see [below for nested schema](#nestedblock--include_headers))
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the source schema. Defaults to `public`.
### Read-Only
diff --git a/docs/resources/table.md b/docs/resources/table.md
index 8f2ab959..db702ead 100644
--- a/docs/resources/table.md
+++ b/docs/resources/table.md
@@ -48,6 +48,7 @@ resource "materialize_table" "simple_table" {
- `comment` (String) **Private Preview** Comment on an object in the database.
- `database_name` (String) The identifier for the table database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the table schema. Defaults to `public`.
### Read-Only
diff --git a/docs/resources/table_grant.md b/docs/resources/table_grant.md
index 35a39365..4d834aa2 100644
--- a/docs/resources/table_grant.md
+++ b/docs/resources/table_grant.md
@@ -35,6 +35,10 @@ resource "materialize_table_grant" "table_grant_usage" {
- `schema_name` (String) The schema that the table being to.
- `table_name` (String) The table that is being granted on.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/table_grant_default_privilege.md b/docs/resources/table_grant_default_privilege.md
index cf43994d..1e4e4e5d 100644
--- a/docs/resources/table_grant_default_privilege.md
+++ b/docs/resources/table_grant_default_privilege.md
@@ -36,6 +36,7 @@ resource "materialize_table_grant_default_privilege" "example" {
### Optional
- `database_name` (String) The default privilege will apply only to objects created in this database, if specified.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The default privilege will apply only to objects created in this schema, if specified.
### Read-Only
diff --git a/docs/resources/type.md b/docs/resources/type.md
index b12f116b..76b8c8bc 100644
--- a/docs/resources/type.md
+++ b/docs/resources/type.md
@@ -49,6 +49,7 @@ resource "materialize_type" "map_type" {
- `list_properties` (Block List, Max: 1) List properties. (see [below for nested schema](#nestedblock--list_properties))
- `map_properties` (Block List, Max: 1) Map properties. (see [below for nested schema](#nestedblock--map_properties))
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `row_properties` (Block List) Row properties. (see [below for nested schema](#nestedblock--row_properties))
- `schema_name` (String) The identifier for the type schema. Defaults to `public`.
diff --git a/docs/resources/type_grant.md b/docs/resources/type_grant.md
index 42083a5c..bf463577 100644
--- a/docs/resources/type_grant.md
+++ b/docs/resources/type_grant.md
@@ -34,6 +34,10 @@ resource "materialize_type_grant" "type_grant_usage" {
- `schema_name` (String) The schema that the type being to.
- `type_name` (String) The type that is being granted on.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/docs/resources/type_grant_default_privilege.md b/docs/resources/type_grant_default_privilege.md
index c01a0d9b..c42c2064 100644
--- a/docs/resources/type_grant_default_privilege.md
+++ b/docs/resources/type_grant_default_privilege.md
@@ -35,6 +35,7 @@ resource "materialize_type_grant_default_privilege" "example" {
### Optional
- `database_name` (String) The default privilege will apply only to objects created in this database, if specified.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The default privilege will apply only to objects created in this schema, if specified.
### Read-Only
diff --git a/docs/resources/user.md b/docs/resources/user.md
new file mode 100644
index 00000000..507d54ab
--- /dev/null
+++ b/docs/resources/user.md
@@ -0,0 +1,44 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "materialize_user Resource - terraform-provider-materialize"
+subcategory: ""
+description: |-
+
+---
+
+# materialize_user (Resource)
+
+
+
+## Example Usage
+
+```terraform
+resource "materialize_user" "example_user" {
+ email = "example-user@example.com"
+ roles = ["Member", "Admin"]
+}
+```
+
+
+## Schema
+
+### Required
+
+- `email` (String) The email address of the user. This must be unique across all users in the organization.
+- `roles` (List of String) The roles to assign to the user. Allowed values are 'Member' and 'Admin'.
+
+### Read-Only
+
+- `auth_provider` (String) The authentication provider for the user.
+- `id` (String) The ID of this resource.
+- `metadata` (String)
+- `verified` (Boolean)
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+# Users can be imported using the user id:
+terraform import materialize_user.example_user
+```
diff --git a/docs/resources/view.md b/docs/resources/view.md
index 514bc322..6b55d8ef 100644
--- a/docs/resources/view.md
+++ b/docs/resources/view.md
@@ -50,6 +50,7 @@ resource "materialize_view" "simple_view" {
- `comment` (String) **Private Preview** Comment on an object in the database.
- `database_name` (String) The identifier for the view database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
- `schema_name` (String) The identifier for the view schema. Defaults to `public`.
### Read-Only
diff --git a/docs/resources/view_grant.md b/docs/resources/view_grant.md
index 002d2585..2f3615b1 100644
--- a/docs/resources/view_grant.md
+++ b/docs/resources/view_grant.md
@@ -34,6 +34,10 @@ resource "materialize_view_grant" "view_grant_select" {
- `schema_name` (String) The schema that the view being to.
- `view_name` (String) The view that is being granted on.
+### Optional
+
+- `region` (String) The region to use for the resource connection. If not set, the default region is used.
+
### Read-Only
- `id` (String) The ID of this resource.
diff --git a/examples/data-sources/materialize_region/data-source.tf b/examples/data-sources/materialize_region/data-source.tf
new file mode 100644
index 00000000..e08c1375
--- /dev/null
+++ b/examples/data-sources/materialize_region/data-source.tf
@@ -0,0 +1,5 @@
+data "materialize_region" "all" {}
+
+output "region" {
+ value = data.materialize_region.all
+}
diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf
index e2d0e95b..d37ea23c 100644
--- a/examples/provider/provider.tf
+++ b/examples/provider/provider.tf
@@ -1,8 +1,5 @@
# Configuration-based authentication
provider "materialize" {
- host = var.materialize_host # optionally use MZ_HOST env var
- user = var.materialize_user # optionally use MZ_USER env var
- password = var.materialize_password # optionally use MZ_PASSWORD env var
- port = var.materialize_port # optionally use MZ_PORT env var
- database = var.materialize_database # optionally use MZ_DATABASE env var
+ password = var.materialize_password # optionally use MZ_PASSWORD env var
+ default_region = "aws/us-east-1" # optionally use MZ_REGION env var
}
diff --git a/examples/resources/materialize_app_password/import.sh b/examples/resources/materialize_app_password/import.sh
new file mode 100644
index 00000000..62c873bb
--- /dev/null
+++ b/examples/resources/materialize_app_password/import.sh
@@ -0,0 +1,2 @@
+# App passwords can be imported using the app password id:
+terraform import materialize_app_password.example_app_password
diff --git a/examples/resources/materialize_app_password/resource.tf b/examples/resources/materialize_app_password/resource.tf
new file mode 100644
index 00000000..ca5893ed
--- /dev/null
+++ b/examples/resources/materialize_app_password/resource.tf
@@ -0,0 +1,3 @@
+resource "materialize_app_password" "example_app_password" {
+ name = "example_app_password_name"
+}
diff --git a/examples/resources/materialize_user/import.sh b/examples/resources/materialize_user/import.sh
new file mode 100644
index 00000000..e8a8ea6c
--- /dev/null
+++ b/examples/resources/materialize_user/import.sh
@@ -0,0 +1,2 @@
+# Users can be imported using the user id:
+terraform import materialize_user.example_user
diff --git a/examples/resources/materialize_user/resource.tf b/examples/resources/materialize_user/resource.tf
new file mode 100644
index 00000000..412721fe
--- /dev/null
+++ b/examples/resources/materialize_user/resource.tf
@@ -0,0 +1,4 @@
+resource "materialize_user" "example_user" {
+ email = "example-user@example.com"
+ roles = ["Member", "Admin"]
+}
diff --git a/go.mod b/go.mod
index a53390bd..67e4b19f 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.20
require (
github.com/DATA-DOG/go-sqlmock v1.5.2
+ github.com/golang-jwt/jwt/v5 v5.1.0
github.com/hashicorp/terraform-plugin-docs v0.16.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0
github.com/hashicorp/terraform-plugin-testing v1.5.1
diff --git a/go.sum b/go.sum
index a46b88ae..cdbc1078 100644
--- a/go.sum
+++ b/go.sum
@@ -44,6 +44,8 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU=
+github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
diff --git a/integration/app_password.tf b/integration/app_password.tf
new file mode 100644
index 00000000..c91e04cf
--- /dev/null
+++ b/integration/app_password.tf
@@ -0,0 +1,4 @@
+resource "materialize_app_password" "example_password" {
+ for_each = toset(["1", "2", "3", "4", "5"])
+ name = "example_password_${each.key}"
+}
diff --git a/integration/main.tf b/integration/main.tf
index 5fd18b5c..c31adabc 100644
--- a/integration/main.tf
+++ b/integration/main.tf
@@ -7,10 +7,9 @@ terraform {
}
provider "materialize" {
- host = "materialized"
- user = "mz_system"
- password = "password"
- port = 6877
- database = "materialize"
- sslmode = "disable"
+ endpoint = "http://frontegg:3000"
+ cloud_endpoint = "http://cloud:3001"
+ password = "mzp_1b2a3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
+ database = "materialize"
+ sslmode = "disable"
}
diff --git a/integration/region.tf b/integration/region.tf
new file mode 100644
index 00000000..e08c1375
--- /dev/null
+++ b/integration/region.tf
@@ -0,0 +1,5 @@
+data "materialize_region" "all" {}
+
+output "region" {
+ value = data.materialize_region.all
+}
diff --git a/integration/user.tf b/integration/user.tf
new file mode 100644
index 00000000..6fe069e3
--- /dev/null
+++ b/integration/user.tf
@@ -0,0 +1,5 @@
+resource "materialize_user" "example_user" {
+ for_each = toset(["1", "2", "3", "4", "5"])
+ email = "example-user${each.key}@example.com"
+ roles = ["Member", "Admin"]
+}
diff --git a/mocks/cloud/Dockerfile b/mocks/cloud/Dockerfile
new file mode 100644
index 00000000..1bda83d2
--- /dev/null
+++ b/mocks/cloud/Dockerfile
@@ -0,0 +1,30 @@
+# Start from the official Golang base image
+FROM golang:1.20 as builder
+
+# Set the Current Working Directory inside the container
+WORKDIR /app
+
+# Copy go mod and sum files
+COPY go.mod go.sum ./
+
+# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
+RUN go mod download
+
+# Copy the source from the current directory to the Working Directory inside the container
+COPY . .
+
+# Build the Go app
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o mockserver .
+
+# Start a new stage from scratch
+FROM alpine:latest
+
+RUN apk --no-cache add ca-certificates
+
+WORKDIR /root/
+
+# Copy the Pre-built binary file from the previous stage
+COPY --from=builder /app/mockserver .
+
+# Command to run the executable
+CMD ["./mockserver"]
diff --git a/mocks/cloud/go.mod b/mocks/cloud/go.mod
new file mode 100644
index 00000000..44e380d8
--- /dev/null
+++ b/mocks/cloud/go.mod
@@ -0,0 +1,5 @@
+module cloud-mockserver
+
+go 1.20
+
+require github.com/golang-jwt/jwt/v5 v5.1.0 // indirect
diff --git a/mocks/cloud/go.sum b/mocks/cloud/go.sum
new file mode 100644
index 00000000..45e080f9
--- /dev/null
+++ b/mocks/cloud/go.sum
@@ -0,0 +1,2 @@
+github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU=
+github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
diff --git a/mocks/cloud/mock_server.go b/mocks/cloud/mock_server.go
new file mode 100644
index 00000000..16fe549f
--- /dev/null
+++ b/mocks/cloud/mock_server.go
@@ -0,0 +1,90 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+)
+
+type Region struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ CloudProvider string `json:"cloudProvider"`
+ URL string `json:"url"`
+ RegionInfo *RegionInfo `json:"regionInfo,omitempty"`
+}
+
+type RegionInfo struct {
+ SqlAddress string `json:"sqlAddress"`
+ HttpAddress string `json:"httpAddress"`
+ Resolvable bool `json:"resolvable"`
+ EnabledAt string `json:"enabledAt"`
+}
+
+type CloudRegion struct {
+ RegionInfo *RegionInfo `json:"regionInfo"`
+}
+
+type CloudProviderResponse struct {
+ Data []Region `json:"data"`
+ NextCursor string `json:"nextCursor,omitempty"`
+}
+
+// Mock data
+var regions = []Region{
+ {
+ ID: "aws/us-east-1",
+ Name: "us-east-1",
+ CloudProvider: "aws",
+ URL: "http://cloud:3001",
+ RegionInfo: &RegionInfo{
+ SqlAddress: "materialized:6877",
+ HttpAddress: "materialized:6875",
+ Resolvable: true,
+ EnabledAt: "2023-01-01T00:00:00Z",
+ },
+ },
+ // Add more mock regions if needed later
+}
+
+func main() {
+ http.HandleFunc("/api/region", regionHandler)
+ http.HandleFunc("/api/cloud-regions", cloudRegionsHandler)
+
+ fmt.Println("Mock Cloud API server is running at http://localhost:3001")
+ log.Fatal(http.ListenAndServe(":3001", nil))
+}
+
+func regionHandler(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case http.MethodGet:
+ mockRegion := CloudRegion{
+ RegionInfo: &RegionInfo{
+ SqlAddress: "materialized:6877",
+ HttpAddress: "materialized:6875",
+ Resolvable: true,
+ EnabledAt: "2023-01-01T00:00:00Z",
+ },
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(mockRegion)
+ case http.MethodPatch:
+ w.WriteHeader(http.StatusOK)
+ case http.MethodDelete:
+ w.WriteHeader(http.StatusAccepted)
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func cloudRegionsHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+ response := CloudProviderResponse{
+ Data: regions,
+ }
+ json.NewEncoder(w).Encode(response)
+}
diff --git a/mocks/frontegg/Dockerfile b/mocks/frontegg/Dockerfile
new file mode 100644
index 00000000..1bda83d2
--- /dev/null
+++ b/mocks/frontegg/Dockerfile
@@ -0,0 +1,30 @@
+# Start from the official Golang base image
+FROM golang:1.20 as builder
+
+# Set the Current Working Directory inside the container
+WORKDIR /app
+
+# Copy go mod and sum files
+COPY go.mod go.sum ./
+
+# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
+RUN go mod download
+
+# Copy the source from the current directory to the Working Directory inside the container
+COPY . .
+
+# Build the Go app
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o mockserver .
+
+# Start a new stage from scratch
+FROM alpine:latest
+
+RUN apk --no-cache add ca-certificates
+
+WORKDIR /root/
+
+# Copy the Pre-built binary file from the previous stage
+COPY --from=builder /app/mockserver .
+
+# Command to run the executable
+CMD ["./mockserver"]
diff --git a/mocks/frontegg/go.mod b/mocks/frontegg/go.mod
new file mode 100644
index 00000000..16aec118
--- /dev/null
+++ b/mocks/frontegg/go.mod
@@ -0,0 +1,3 @@
+module frontegg-mockserver
+
+go 1.20
diff --git a/mocks/frontegg/go.sum b/mocks/frontegg/go.sum
new file mode 100644
index 00000000..e69de29b
diff --git a/mocks/frontegg/mock_server.go b/mocks/frontegg/mock_server.go
new file mode 100644
index 00000000..c47d76ae
--- /dev/null
+++ b/mocks/frontegg/mock_server.go
@@ -0,0 +1,298 @@
+package main
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+)
+
+type AppPassword struct {
+ ClientID string `json:"clientId"`
+ Secret string `json:"secret"`
+ Description string `json:"description"`
+ Owner string `json:"owner"`
+ CreatedAt time.Time `json:"created_at"`
+}
+
+type User struct {
+ ID string `json:"id"`
+ Email string `json:"email"`
+ ProfilePictureURL string `json:"profilePictureUrl"`
+ Verified bool `json:"verified"`
+ Metadata string `json:"metadata"`
+}
+
+type FronteggRole struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+}
+
+type FronteggRolesResponse struct {
+ Items []FronteggRole `json:"items"`
+ Metadata struct {
+ TotalItems int `json:"totalItems"`
+ TotalPages int `json:"totalPages"`
+ } `json:"_metadata"`
+}
+
+var (
+ appPasswords = make(map[string]AppPassword)
+ users = make(map[string]User)
+ mutex = &sync.Mutex{}
+)
+
+func main() {
+ http.HandleFunc("/identity/resources/auth/v1/api-token", handleTokenRequest)
+ http.HandleFunc("/identity/resources/users/api-tokens/v1", handleAppPasswords)
+ http.HandleFunc("/identity/resources/users/v1/", handleUserRequest)
+ http.HandleFunc("/identity/resources/users/v2", handleUserRequest)
+ http.HandleFunc("/identity/resources/roles/v2", handleRolesRequest)
+
+ fmt.Println("Mock Frontegg server is running at http://localhost:3000")
+ log.Fatal(http.ListenAndServe(":3000", nil))
+}
+
+func handleUserRequest(w http.ResponseWriter, r *http.Request) {
+ logRequest(r)
+ switch r.Method {
+ case http.MethodGet:
+ getUser(w, r)
+ case http.MethodDelete:
+ deleteUser(w, r)
+ case http.MethodPost:
+ createUser(w, r)
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func getUser(w http.ResponseWriter, r *http.Request) {
+ userID := strings.TrimPrefix(r.URL.Path, "/identity/resources/users/v1/")
+ if userID == "" {
+ http.Error(w, "User ID is required", http.StatusBadRequest)
+ return
+ }
+
+ user, ok := users[userID]
+ if !ok {
+ http.Error(w, "User not found", http.StatusNotFound)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(user)
+}
+
+func createUser(w http.ResponseWriter, r *http.Request) {
+ var newUser User
+ if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ userID := generateUserID()
+ newUser.ID = userID
+
+ // Store the new user
+ mutex.Lock()
+ users[userID] = newUser
+ mutex.Unlock()
+
+ w.WriteHeader(http.StatusCreated)
+ // Return the created user
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(newUser)
+}
+
+func generateUserID() string {
+ return fmt.Sprintf("user-%d", time.Now().UnixNano())
+}
+
+func deleteUser(w http.ResponseWriter, r *http.Request) {
+ userID := strings.TrimPrefix(r.URL.Path, "/identity/resources/users/v1/")
+ if userID == "" {
+ http.Error(w, "User ID is required", http.StatusBadRequest)
+ return
+ }
+
+ _, ok := users[userID]
+ if !ok {
+ http.Error(w, "User not found", http.StatusNotFound)
+ return
+ }
+
+ delete(users, userID)
+ w.WriteHeader(http.StatusOK)
+}
+
+func handleTokenRequest(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ var payload struct {
+ ClientId string `json:"clientId"`
+ Secret string `json:"secret"`
+ }
+ if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ if payload.ClientId == "1b2a3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d" && payload.Secret == "7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b" {
+ mockToken := createMockJWTToken()
+ response := map[string]string{
+ "accessToken": mockToken,
+ "email": "mz_system",
+ }
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+ } else {
+ http.Error(w, "Invalid credentials", http.StatusUnauthorized)
+ }
+}
+
+func createMockJWTToken() string {
+ header := base64UrlEncode([]byte(`{"alg":"HS256","typ":"JWT"}`))
+ payload := base64UrlEncode([]byte(`{"email":"mz_system","exp":1700000000}`))
+ signature := base64UrlEncode([]byte(`signature`))
+ return fmt.Sprintf("%s.%s.%s", header, payload, signature)
+}
+
+func base64UrlEncode(input []byte) string {
+ encoded := base64.StdEncoding.EncodeToString(input)
+ encoded = strings.ReplaceAll(encoded, "+", "-")
+ encoded = strings.ReplaceAll(encoded, "/", "_")
+ encoded = strings.TrimRight(encoded, "=")
+ return encoded
+}
+
+func handleAppPasswords(w http.ResponseWriter, r *http.Request) {
+ logRequest(r)
+ switch r.Method {
+ case http.MethodPost:
+ createAppPassword(w, r)
+ case http.MethodGet:
+ listAppPasswords(w, r)
+ case http.MethodDelete:
+ deleteAppPassword(w, r)
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func handleRolesRequest(w http.ResponseWriter, r *http.Request) {
+ logRequest(r)
+ roles := []FronteggRole{
+ {ID: "1", Name: "Organization Admin"},
+ {ID: "2", Name: "Organization Member"},
+ }
+
+ response := FronteggRolesResponse{
+ Items: roles,
+ Metadata: struct {
+ TotalItems int `json:"totalItems"`
+ TotalPages int `json:"totalPages"`
+ }{
+ TotalItems: len(roles),
+ TotalPages: 1,
+ },
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(response)
+}
+
+func createAppPassword(w http.ResponseWriter, r *http.Request) {
+ logRequest(r)
+ var req struct {
+ Description string `json:"description"`
+ }
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ // Generate a new app password
+ newAppPassword := AppPassword{
+ ClientID: generateClientID(),
+ Secret: generateSecret(),
+ Description: req.Description,
+ Owner: "mockOwner",
+ CreatedAt: time.Now(),
+ }
+
+ // Store the new app password
+ mutex.Lock()
+ appPasswords[newAppPassword.ClientID] = newAppPassword
+ mutex.Unlock()
+
+ // Send the response back
+ sendResponse(w, http.StatusCreated, newAppPassword)
+}
+
+func listAppPasswords(w http.ResponseWriter, r *http.Request) {
+ mutex.Lock()
+ passwords := make([]AppPassword, 0, len(appPasswords))
+ for _, password := range appPasswords {
+ passwords = append(passwords, password)
+ }
+ mutex.Unlock()
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(passwords)
+}
+
+func deleteAppPassword(w http.ResponseWriter, r *http.Request) {
+ clientID := r.URL.Query().Get("clientId")
+ if clientID == "" {
+ http.Error(w, "Client ID is required", http.StatusBadRequest)
+ return
+ }
+
+ mutex.Lock()
+ delete(appPasswords, clientID)
+ mutex.Unlock()
+
+ w.WriteHeader(http.StatusOK)
+}
+
+// generateClientID generates a unique client ID.
+func generateClientID() string {
+ return fmt.Sprintf("client-%d", time.Now().UnixNano())
+}
+
+// generateSecret generates a secret.
+func generateSecret() string {
+ return fmt.Sprintf("secret-%d", time.Now().UnixNano())
+}
+
+func sendResponse(w http.ResponseWriter, statusCode int, payload interface{}) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(statusCode)
+ if payload != nil {
+ responseBytes, _ := json.Marshal(payload)
+ fmt.Printf("Response body: %s\n", string(responseBytes))
+ w.Write(responseBytes)
+ }
+}
+
+func logRequest(r *http.Request) {
+ fmt.Printf("Received request: %s %s\n", r.Method, r.URL.Path)
+ if r.Body != nil {
+ bodyBytes, err := io.ReadAll(r.Body)
+ if err == nil {
+ fmt.Printf("Request body: %s\n", string(bodyBytes))
+ // Important: Restore the body for further reading
+ r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
+ }
+ }
+}
diff --git a/pkg/clients/cloud_client.go b/pkg/clients/cloud_client.go
new file mode 100644
index 00000000..68fd22f1
--- /dev/null
+++ b/pkg/clients/cloud_client.go
@@ -0,0 +1,164 @@
+package clients
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "strconv"
+ "strings"
+)
+
+// RegionInfo holds the detailed information about a region from the Cloud API
+type RegionInfo struct {
+ SqlAddress string `json:"sqlAddress"`
+ HttpAddress string `json:"httpAddress"`
+ Resolvable bool `json:"resolvable"`
+ EnabledAt string `json:"enabledAt"`
+}
+
+// Region holds the connection details for an active region
+type CloudRegion struct {
+ RegionInfo *RegionInfo `json:"regionInfo"`
+}
+
+// CloudProvider contains the information about a cloud provider and its region
+type CloudProvider struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Url string `json:"url"`
+ CloudProvider string `json:"cloudProvider"`
+}
+
+// CloudProviderResponse represents the response for listing cloud providers
+type CloudProviderResponse struct {
+ Data []CloudProvider `json:"data"`
+ NextCursor string `json:"nextCursor,omitempty"`
+}
+
+// CloudAPIClient is a client for interacting with the Materialize Cloud API
+type CloudAPIClient struct {
+ HTTPClient *http.Client
+ FronteggClient *FronteggClient
+ Endpoint string
+}
+
+// NewCloudAPIClient creates a new Cloud API client
+func NewCloudAPIClient(fronteggClient *FronteggClient, cloudAPIEndpoint string) *CloudAPIClient {
+ return &CloudAPIClient{
+ HTTPClient: &http.Client{},
+ FronteggClient: fronteggClient,
+ Endpoint: cloudAPIEndpoint,
+ }
+}
+
+// ListCloudProviders fetches the list of cloud providers and their regions
+func (c *CloudAPIClient) ListCloudProviders(ctx context.Context) ([]CloudProvider, error) {
+ providersEndpoint := fmt.Sprintf("%s/api/cloud-regions", c.Endpoint)
+
+ // Reuse the FronteggClient's HTTPClient which already includes the Authorization token.
+ resp, err := c.FronteggClient.HTTPClient.Get(providersEndpoint)
+ if err != nil {
+ return nil, fmt.Errorf("error listing cloud providers: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response body: %v", err)
+ }
+ return nil, fmt.Errorf("cloud API returned non-200 status code: %d, body: %s", resp.StatusCode, string(body))
+ }
+
+ var response CloudProviderResponse
+ if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
+ return nil, err
+ }
+
+ log.Printf("[DEBUG] Cloud providers response body: %+v\n", response)
+
+ return response.Data, nil
+}
+
+// GetRegionDetails fetches the details for a given region
+func (c *CloudAPIClient) GetRegionDetails(ctx context.Context, provider CloudProvider) (*CloudRegion, error) {
+ regionEndpoint := fmt.Sprintf("%s/api/region", provider.Url)
+
+ resp, err := c.FronteggClient.HTTPClient.Get(regionEndpoint)
+ if err != nil {
+ return nil, fmt.Errorf("error retrieving region details: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response body: %v", err)
+ }
+ return nil, fmt.Errorf("cloud API returned non-200 status code: %d, body: %s", resp.StatusCode, string(body))
+ }
+
+ log.Printf("[DEBUG] Region details response body: %+v\n", resp.Body)
+
+ var region CloudRegion
+ if err := json.NewDecoder(resp.Body).Decode(®ion); err != nil {
+ return nil, err
+ }
+
+ log.Printf("[DEBUG] Region details response body: %+v\n", region)
+
+ return ®ion, nil
+}
+
+// GetHost retrieves the SQL address for a specified region
+func (c *CloudAPIClient) GetHost(ctx context.Context, regionID string) (string, error) {
+ providers, err := c.ListCloudProviders(ctx)
+ if err != nil {
+ return "", err
+ }
+
+ var provider *CloudProvider
+ for _, p := range providers {
+ if p.ID == regionID {
+ provider = &p
+ break
+ }
+ }
+
+ if provider == nil {
+ return "", fmt.Errorf("provider for region '%s' not found", regionID)
+ }
+
+ region, err := c.GetRegionDetails(ctx, *provider)
+ if err != nil {
+ return "", err
+ }
+
+ if region.RegionInfo == nil || !region.RegionInfo.Resolvable {
+ return "", fmt.Errorf("region '%s' is not enabled", regionID)
+ }
+
+ return region.RegionInfo.SqlAddress, nil
+}
+
+func SplitHostPort(hostPortStr string) (host string, port int, err error) {
+ parts := strings.Split(hostPortStr, ":")
+ switch len(parts) {
+ case 1:
+ // Only host is provided, return the default port
+ return parts[0], 6875, nil
+ case 2:
+ // Both host and port are provided, return both
+ port, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return "", 0, fmt.Errorf("invalid port: %v", err)
+ }
+ return parts[0], port, nil
+ default:
+ // Invalid format
+ return "", 0, fmt.Errorf("invalid host:port format")
+ }
+}
diff --git a/pkg/clients/cloud_client_test.go b/pkg/clients/cloud_client_test.go
new file mode 100644
index 00000000..adf8d14f
--- /dev/null
+++ b/pkg/clients/cloud_client_test.go
@@ -0,0 +1,219 @@
+package clients
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+type MockFronteggService struct {
+ MockResponseStatus int
+}
+
+func (m *MockFronteggService) RoundTrip(req *http.Request) (*http.Response, error) {
+ // Check the requested URL and return a response accordingly
+ if strings.HasSuffix(req.URL.Path, "/api/cloud-regions") {
+ // Mock response data
+ data := CloudProviderResponse{
+ Data: []CloudProvider{
+ {ID: "aws/us-east-1", Name: "us-east-1", Url: "http://mockendpoint", CloudProvider: "aws"},
+ {ID: "aws/eu-west-1", Name: "eu-west-1", Url: "http://mockendpoint", CloudProvider: "aws"},
+ },
+ }
+
+ // Convert response data to JSON
+ respData, _ := json.Marshal(data)
+
+ // Create a new HTTP response with the JSON data and the specified status code
+ return &http.Response{
+ StatusCode: m.MockResponseStatus,
+ Body: io.NopCloser(bytes.NewReader(respData)),
+ Header: make(http.Header),
+ }, nil
+ } else if strings.HasSuffix(req.URL.Path, "/api/region") {
+ // Return mock response for GetRegionDetails
+ details := CloudRegion{
+ RegionInfo: &RegionInfo{
+ SqlAddress: "sql.materialize.com",
+ HttpAddress: "http.materialize.com",
+ Resolvable: true,
+ EnabledAt: "2021-01-01T00:00:00Z",
+ },
+ }
+ respData, _ := json.Marshal(details)
+ return &http.Response{
+ StatusCode: m.MockResponseStatus,
+ Body: io.NopCloser(bytes.NewReader(respData)),
+ Header: make(http.Header),
+ }, nil
+ }
+ return nil, fmt.Errorf("no mock available for the requested endpoint")
+}
+
+func TestCloudAPIClient_ListCloudProviders(t *testing.T) {
+ mockService := &MockFronteggService{
+ MockResponseStatus: http.StatusOK,
+ }
+ mockClient := &http.Client{Transport: mockService}
+ apiClient := &CloudAPIClient{
+ FronteggClient: &FronteggClient{HTTPClient: mockClient},
+ Endpoint: "http://mockendpoint.com",
+ }
+
+ // Call the method to test
+ providers, err := apiClient.ListCloudProviders(context.Background())
+ if err != nil {
+ t.Fatalf("ListCloudProviders() error: %v", err)
+ }
+
+ // Verify the results
+ wantProviderCount := 2
+ if len(providers) != wantProviderCount {
+ t.Errorf("ListCloudProviders() got %v providers, want %v", len(providers), wantProviderCount)
+ }
+}
+
+func TestCloudAPIClient_GetRegionDetails(t *testing.T) {
+ mockService := &MockFronteggService{
+ MockResponseStatus: http.StatusOK,
+ }
+ mockClient := &http.Client{Transport: mockService}
+ apiClient := &CloudAPIClient{
+ FronteggClient: &FronteggClient{HTTPClient: mockClient},
+ Endpoint: "http://mockendpoint.com",
+ }
+
+ provider := CloudProvider{
+ ID: "aws/us-east-1",
+ Name: "us-east-1",
+ Url: "http://mockendpoint.com/api/region",
+ }
+
+ // Call the method to test
+ region, err := apiClient.GetRegionDetails(context.Background(), provider)
+ if err != nil {
+ t.Fatalf("GetRegionDetails() error: %v", err)
+ }
+
+ // Verify the results
+ wantSqlAddress := "sql.materialize.com"
+ if region.RegionInfo.SqlAddress != wantSqlAddress {
+ t.Errorf("GetRegionDetails() got SqlAddress = %v, want %v", region.RegionInfo.SqlAddress, wantSqlAddress)
+ }
+}
+
+func TestCloudAPIClient_GetHost(t *testing.T) {
+ mockService := &MockFronteggService{
+ MockResponseStatus: http.StatusOK,
+ }
+ mockClient := &http.Client{Transport: mockService}
+ apiClient := &CloudAPIClient{
+ FronteggClient: &FronteggClient{HTTPClient: mockClient},
+ Endpoint: "http://mockendpoint.com",
+ }
+
+ regionID := "aws/us-east-1"
+
+ sqlAddress, err := apiClient.GetHost(context.Background(), regionID)
+ if err != nil {
+ t.Fatalf("GetHost() error: %v", err)
+ }
+
+ // Verify the results
+ wantSqlAddress := "sql.materialize.com"
+ if sqlAddress != wantSqlAddress {
+ t.Errorf("GetHost() got SqlAddress = %v, want %v", sqlAddress, wantSqlAddress)
+ }
+}
+
+func TestCloudAPIClient_ListCloudProviders_ErrorResponse(t *testing.T) {
+ mockService := &MockFronteggService{
+ // Mock the HTTP response to return an error status code:
+ MockResponseStatus: http.StatusInternalServerError,
+ }
+ mockClient := &http.Client{Transport: mockService}
+ apiClient := &CloudAPIClient{
+ FronteggClient: &FronteggClient{HTTPClient: mockClient},
+ Endpoint: "http://mockendpoint.com",
+ }
+
+ // Call the method to test
+ _, err := apiClient.ListCloudProviders(context.Background())
+
+ // Verify that an error is returned when the server responds with an error status code
+ require.Error(t, err)
+}
+
+func TestCloudAPIClient_GetRegionDetails_ErrorResponse(t *testing.T) {
+ mockService := &MockFronteggService{
+ // Mock the HTTP response to return an error status code
+ MockResponseStatus: http.StatusInternalServerError,
+ }
+ mockClient := &http.Client{Transport: mockService}
+ apiClient := &CloudAPIClient{
+ FronteggClient: &FronteggClient{HTTPClient: mockClient},
+ Endpoint: "http://mockendpoint.com",
+ }
+ provider := CloudProvider{
+ ID: "aws/us-east-1",
+ Name: "us-east-1",
+ Url: "http://mockendpoint.com/api/region",
+ }
+
+ // Call the method to test
+ _, err := apiClient.GetRegionDetails(context.Background(), provider)
+
+ // Verify that an error is returned when the server responds with an error status code
+ require.Error(t, err)
+}
+
+func TestCloudAPIClient_GetHost_RegionNotFound(t *testing.T) {
+ mockService := &MockFronteggService{
+ MockResponseStatus: http.StatusOK,
+ }
+ mockClient := &http.Client{Transport: mockService}
+ apiClient := &CloudAPIClient{
+ FronteggClient: &FronteggClient{HTTPClient: mockClient},
+ Endpoint: "http://mockendpoint.com",
+ }
+ regionID := "non-existent-region"
+
+ // Call the method to test
+ _, err := apiClient.GetHost(context.Background(), regionID)
+
+ // Verify that an error is returned when the region is not found
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "provider for region 'non-existent-region' not found")
+}
+
+func TestNewCloudAPIClient(t *testing.T) {
+ // Create a FronteggClient instance for testing
+ fronteggClient := &FronteggClient{}
+
+ // Call the NewCloudAPIClient function with a custom API endpoint
+ customEndpoint := "http://custom-endpoint.com/api"
+ cloudAPIClient := NewCloudAPIClient(fronteggClient, customEndpoint)
+
+ // Assert that the returned CloudAPIClient has the expected properties
+ require.NotNil(t, cloudAPIClient)
+ require.Equal(t, fronteggClient, cloudAPIClient.FronteggClient)
+ require.NotNil(t, cloudAPIClient.HTTPClient)
+ require.Equal(t, customEndpoint, cloudAPIClient.Endpoint)
+
+ // Call the NewCloudAPIClient function with a different custom API endpoint
+ anotherCustomEndpoint := "http://another-custom-endpoint.com/api"
+ cloudAPIClient = NewCloudAPIClient(fronteggClient, anotherCustomEndpoint)
+
+ // Assert that the returned CloudAPIClient has the updated custom endpoint
+ require.NotNil(t, cloudAPIClient)
+ require.Equal(t, fronteggClient, cloudAPIClient.FronteggClient)
+ require.NotNil(t, cloudAPIClient.HTTPClient)
+ require.Equal(t, anotherCustomEndpoint, cloudAPIClient.Endpoint)
+}
diff --git a/pkg/clients/db_client.go b/pkg/clients/db_client.go
new file mode 100644
index 00000000..132543fd
--- /dev/null
+++ b/pkg/clients/db_client.go
@@ -0,0 +1,53 @@
+package clients
+
+import (
+ "fmt"
+ "net/url"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/jmoiron/sqlx"
+)
+
+type DBClient struct {
+ *sqlx.DB
+}
+
+func NewDBClient(host, user, password string, port int, database, application_name_suffix, version, sslmode string) (*DBClient, diag.Diagnostics) {
+ var diags diag.Diagnostics
+
+ application_name := fmt.Sprintf("terraform-provider-materialize v%s", version)
+ if application_name_suffix != "" {
+ application_name += " " + application_name_suffix
+ }
+
+ connStr := buildConnectionString(host, user, password, port, database, sslmode, application_name)
+ db, err := sqlx.Open("pgx", connStr)
+ if err != nil {
+ diags = append(diags, diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Unable to create database client",
+ Detail: fmt.Sprintf("Unable to authenticate user for database: %s", err),
+ })
+ return nil, diags
+ }
+ return &DBClient{DB: db}, diags
+}
+
+func buildConnectionString(host, user, password string, port int, database, sslmode, application_name string) string {
+ url := &url.URL{
+ Scheme: "postgres",
+ User: url.UserPassword(user, password),
+ Host: fmt.Sprintf("%s:%d", host, port),
+ Path: database,
+ RawQuery: url.Values{
+ "application_name": {application_name},
+ "sslmode": {sslmode},
+ }.Encode(),
+ }
+
+ return url.String()
+}
+
+func (c *DBClient) SQLX() *sqlx.DB {
+ return c.DB
+}
diff --git a/pkg/clients/db_client_test.go b/pkg/clients/db_client_test.go
new file mode 100644
index 00000000..2929cdcf
--- /dev/null
+++ b/pkg/clients/db_client_test.go
@@ -0,0 +1,27 @@
+package clients
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestConnectionString(t *testing.T) {
+ r := require.New(t)
+ c := buildConnectionString("host", "user", "pass", 6875, "database", "require", "tf")
+ r.Equal(`postgres://user:pass@host:6875/database?application_name=tf&sslmode=require`, c)
+}
+
+func TestConnectionStringTesting(t *testing.T) {
+ r := require.New(t)
+ c := buildConnectionString("host", "user", "pass", 6875, "database", "disable", "tf")
+ r.Equal(`postgres://user:pass@host:6875/database?application_name=tf&sslmode=disable`, c)
+}
+
+func TestNewDBClientFailure(t *testing.T) {
+ r := require.New(t)
+
+ client, diags := NewDBClient("localhost", "user", "pass", 6875, "database", "tf-provider", "v0.1.0", "invalid-sslmode")
+ r.NotEmpty(diags)
+ r.Nil(client)
+}
diff --git a/pkg/clients/frontegg_client.go b/pkg/clients/frontegg_client.go
new file mode 100644
index 00000000..c7530ecc
--- /dev/null
+++ b/pkg/clients/frontegg_client.go
@@ -0,0 +1,245 @@
+package clients
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "regexp"
+ "strings"
+ "time"
+
+ "github.com/golang-jwt/jwt/v5"
+)
+
+// FronteggClient struct to encapsulate the http.Client with additional properties
+type FronteggClient struct {
+ HTTPClient *http.Client
+ Token string
+ Email string
+ Endpoint string
+ TokenExpiry time.Time
+ Password string
+}
+
+// NewFronteggClient function for initializing a new Frontegg client with an auth token
+func NewFronteggClient(ctx context.Context, password, endpoint string) (*FronteggClient, error) {
+ token, email, tokenExpiry, err := getToken(ctx, password, endpoint)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get token: %v", err)
+ }
+
+ transport := &tokenTransport{
+ Token: token,
+ Transport: http.DefaultTransport,
+ }
+
+ client := &http.Client{Transport: transport}
+
+ return &FronteggClient{
+ HTTPClient: client,
+ Token: token,
+ Email: email,
+ Endpoint: endpoint,
+ TokenExpiry: tokenExpiry.Add(-time.Duration(0.5*float64(time.Until(tokenExpiry).Nanoseconds())) * time.Nanosecond),
+ Password: password,
+ }, nil
+}
+
+// tokenTransport struct to add the Authorization header to each request
+type tokenTransport struct {
+ Token string
+ Transport http.RoundTripper
+}
+
+// RoundTrip method to execute the request with the token
+func (t *tokenTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+ req2 := cloneRequest(req)
+ req2.Header.Set("Authorization", "Bearer "+t.Token)
+ return t.Transport.RoundTrip(req2)
+}
+
+// GetToken function to authenticate with the Frontegg API and retrieve a token
+func getToken(ctx context.Context, password string, endpoint string) (string, string, time.Time, error) {
+ clientId, secretKey, err := parseAppPassword(password)
+ if err != nil {
+ return "", "", time.Time{}, err
+ }
+
+ adminEndpoint := fmt.Sprintf("%s/identity/resources/auth/v1/api-token", endpoint)
+
+ payload := map[string]string{
+ "clientId": clientId,
+ "secret": secretKey,
+ }
+ payloadBytes, err := json.Marshal(payload)
+ if err != nil {
+ return "", "", time.Time{}, err
+ }
+
+ req, err := http.NewRequestWithContext(ctx, "POST", adminEndpoint, bytes.NewBuffer(payloadBytes))
+ if err != nil {
+ return "", "", time.Time{}, err
+ }
+ req.Header.Add("Content-Type", "application/json")
+
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return "", "", time.Time{}, err
+ }
+ defer resp.Body.Close()
+
+ // Read the response body into the 'body' variable
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", "", time.Time{}, err
+ }
+
+ if resp.StatusCode != http.StatusOK {
+ return "", "", time.Time{}, fmt.Errorf("authentication failed: %s", string(body))
+ }
+
+ var result map[string]interface{}
+ if err := json.Unmarshal(body, &result); err != nil {
+ return "", "", time.Time{}, err
+ }
+
+ tokenString, ok := result["accessToken"].(string)
+ if !ok {
+ return "", "", time.Time{}, errors.New("access token not found in the response")
+ }
+
+ // Parse the token without verifying the signature.
+ token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
+ if err != nil {
+ return "", "", time.Time{}, fmt.Errorf("error parsing token: %v", err)
+ }
+
+ claims, ok := token.Claims.(jwt.MapClaims)
+ if !ok {
+ return "", "", time.Time{}, errors.New("invalid token claims")
+ }
+
+ email, ok := claims["email"].(string)
+ if !ok {
+ return "", "", time.Time{}, errors.New("email claim not found in token")
+ }
+
+ var tokenExpiry time.Time
+ if expiresIn, ok := result["expiresIn"].(float64); ok {
+ tokenExpiry = time.Now().Add(time.Duration(expiresIn) * time.Second)
+ } else {
+ // Default expiry time if not provided in the response
+ tokenExpiry = time.Now().Add(1 * time.Hour)
+ }
+
+ return tokenString, email, tokenExpiry, nil
+}
+
+// Get the token from the FronteggClient
+func (c *FronteggClient) GetToken() string {
+ return c.Token
+}
+
+// Get the email from the FronteggClient
+func (c *FronteggClient) GetEmail() string {
+ return c.Email
+}
+
+// Get the endpoint from the FronteggClient
+func (c *FronteggClient) GetEndpoint() string {
+ return c.Endpoint
+}
+
+// Get the token expiry from the FronteggClient
+func (c *FronteggClient) GetTokenExpiry() time.Time {
+ return c.TokenExpiry
+}
+
+// Get the password from the FronteggClient
+func (c *FronteggClient) GetPassword() string {
+ return c.Password
+}
+
+// cloneRequest creates a deep copy of an HTTP request to enable safe modifications
+// while preserving concurrency safety, immutability, and reusability.
+// https://stackoverflow.com/questions/62017146/http-request-clone-is-not-deep-clone
+func cloneRequest(r *http.Request) *http.Request {
+ // Deep copy the request
+ r2 := new(http.Request)
+ *r2 = *r
+
+ // Deep copy the URL
+ r2.URL = new(url.URL)
+ *r2.URL = *r.URL
+
+ // Deep copy the Header
+ r2.Header = make(http.Header, len(r.Header))
+ for k, s := range r.Header {
+ r2.Header[k] = append([]string(nil), s...)
+ }
+ return r2
+}
+
+func parseAppPassword(password string) (string, string, error) {
+ strippedPassword := strings.TrimPrefix(password, "mzp_")
+ var clientId, secretKey string
+
+ re := regexp.MustCompile("[^0-9a-fA-F]")
+ filteredChars := re.ReplaceAllString(strippedPassword, "")
+
+ if len(filteredChars) < 64 {
+ return "", "", fmt.Errorf("invalid app password length: %d", len(filteredChars))
+ }
+
+ clientId = formatDashlessUuid(filteredChars[0:32])
+ secretKey = formatDashlessUuid(filteredChars[32:])
+
+ return clientId, secretKey, nil
+}
+
+func formatDashlessUuid(dashlessUuid string) string {
+ parts := []string{
+ dashlessUuid[0:8],
+ dashlessUuid[8:12],
+ dashlessUuid[12:16],
+ dashlessUuid[16:20],
+ dashlessUuid[20:],
+ }
+ return strings.Join(parts, "-")
+}
+
+func (c *FronteggClient) NeedsTokenRefresh() error {
+ if time.Now().After(c.TokenExpiry) {
+ return fmt.Errorf("token expired and needs refresh")
+ }
+ return nil
+}
+
+func (c *FronteggClient) RefreshToken() error {
+ log.Printf("[DEBUG] Refreshing Frontegg: %v\n", c)
+
+ token, email, tokenExpiry, err := getToken(context.Background(), c.Password, c.Endpoint)
+ if err != nil {
+ return fmt.Errorf("failed to get token: %v", err)
+ }
+
+ transport := &tokenTransport{
+ Token: token,
+ Transport: http.DefaultTransport,
+ }
+
+ client := &http.Client{Transport: transport}
+
+ c.HTTPClient = client
+ c.Token = token
+ c.Email = email
+ c.TokenExpiry = tokenExpiry.Add(-time.Duration(0.5*float64(time.Until(tokenExpiry).Nanoseconds())) * time.Nanosecond)
+
+ return nil
+}
diff --git a/pkg/clients/frontegg_client_test.go b/pkg/clients/frontegg_client_test.go
new file mode 100644
index 00000000..121257a0
--- /dev/null
+++ b/pkg/clients/frontegg_client_test.go
@@ -0,0 +1,133 @@
+package clients
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/golang-jwt/jwt/v5"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewFronteggClient(t *testing.T) {
+ // Start a local HTTP server to mock the Frontegg API
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path == "/identity/resources/auth/v1/api-token" {
+ w.Header().Set("Content-Type", "application/json")
+ response := map[string]string{
+ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im16X3N5c3RlbSIsImV4cCI6MTcwMDAwMDAwMH0.c2lnbmF0dXJl",
+ }
+ json.NewEncoder(w).Encode(response)
+ } else {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ }))
+ defer server.Close()
+
+ // Use the server's URL as the endpoint
+ endpoint := server.URL
+ password := "mzp_" + strings.Repeat("a", 64)
+
+ // Create the Frontegg client using the mocked server and context
+ fronteggClient, err := NewFronteggClient(context.Background(), password, endpoint)
+ require.NoError(t, err, "Error should be nil")
+ require.NotNil(t, fronteggClient, "Frontegg client should not be nil")
+
+ // The token should be set correctly in the Frontegg client
+ require.Equal(t, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im16X3N5c3RlbSIsImV4cCI6MTcwMDAwMDAwMH0.c2lnbmF0dXJl", fronteggClient.Token, "Token should be set correctly in the Frontegg client")
+}
+
+func TestFronteggClient_AuthenticationError(t *testing.T) {
+ // Start a local HTTP server to mock the Frontegg API with an error response
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusUnauthorized) // Simulate an authentication error
+ }))
+ defer server.Close()
+
+ // Use the server's URL as the endpoint
+ endpoint := server.URL
+ password := "mzp_" + strings.Repeat("a", 64)
+
+ // Create the Frontegg client using the mocked server and context
+ _, err := NewFronteggClient(context.Background(), password, endpoint)
+ require.Error(t, err, "Authentication error should result in an error")
+}
+
+func TestFronteggClient_TokenRefresh(t *testing.T) {
+ // Create a mock HTTP server to simulate the Frontegg API
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path == "/identity/resources/auth/v1/api-token" {
+ // Generate a valid JWT token
+ token := generateValidJWTToken()
+
+ // Simulate a successful token refresh response with the generated JWT token
+ w.Header().Set("Content-Type", "application/json")
+ response := map[string]string{
+ "accessToken": token,
+ }
+ json.NewEncoder(w).Encode(response)
+ } else {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ }))
+ defer server.Close()
+
+ // Use the mock server's URL as the endpoint
+ endpoint := server.URL
+ password := "mzp_" + strings.Repeat("a", 64)
+
+ // Create the Frontegg client using the mock server and context
+ fronteggClient, err := NewFronteggClient(context.Background(), password, endpoint)
+ require.NoError(t, err, "Error should be nil")
+ require.NotNil(t, fronteggClient, "Frontegg client should not be nil")
+
+ // The token should be initially set correctly in the Frontegg client
+ require.NotEmpty(t, fronteggClient.Token, "Token should be set correctly in the Frontegg client")
+
+ // Verify that the client does not detect the need for token refresh immediately
+ require.NoError(t, fronteggClient.NeedsTokenRefresh(), "Token should not be considered expired")
+}
+
+func generateValidJWTToken() string {
+ // Create a JWT token with the correct format
+ token := jwt.New(jwt.SigningMethodHS256)
+ claims := token.Claims.(jwt.MapClaims)
+ claims["email"] = "test@example.com" // Add relevant claims
+ claims["exp"] = time.Now().Add(time.Hour).Unix() // Set expiration time
+
+ // Sign the token with a secret key (you can use a random key for testing)
+ secretKey := []byte("your-secret-key")
+ tokenString, _ := token.SignedString(secretKey)
+
+ return tokenString
+}
+
+func TestFronteggClient_NeedsTokenRefresh(t *testing.T) {
+ // Create a Frontegg client with an expired token
+ fronteggClient := &FronteggClient{
+ Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im16X3N5c3RlbSIsImV4cCI6MTYwMDAwMDAwMH0.c2lnbmF0dXJl",
+ Email: "test@example.com",
+ Endpoint: "http://mockedendpoint",
+ TokenExpiry: time.Now().Add(-time.Hour), // Expired token
+ Password: "mzp_" + strings.Repeat("a", 64),
+ }
+
+ // Verify that the client correctly detects the need for token refresh
+ require.Error(t, fronteggClient.NeedsTokenRefresh(), "Token should be considered expired and require refresh")
+}
+
+func TestParseAppPassword(t *testing.T) {
+ validPassword := "mzp_" + strings.Repeat("a", 64)
+ clientId, secretKey, err := parseAppPassword(validPassword)
+ require.NoError(t, err, "Parsing valid password should not result in an error")
+ require.Equal(t, "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", clientId, "Client ID should match")
+ require.Equal(t, "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", secretKey, "Secret Key should match")
+
+ invalidPassword := "invalid_password"
+ _, _, err = parseAppPassword(invalidPassword)
+ require.Error(t, err, "Parsing invalid password should result in an error")
+}
diff --git a/pkg/clients/helpers.go b/pkg/clients/helpers.go
new file mode 100644
index 00000000..64a0723a
--- /dev/null
+++ b/pkg/clients/helpers.go
@@ -0,0 +1,47 @@
+package clients
+
+import (
+ "fmt"
+ "strings"
+ "time"
+)
+
+type AppPassword struct {
+ ClientID string `json:"clientId"`
+ Secret string `json:"secret"`
+ Description string `json:"description"`
+ Owner string `json:"owner"`
+ CreatedAt time.Time `json:"created_at"`
+}
+
+type Region string
+
+// Role represents the Frontegg role structure.
+type Role struct {
+ ID string `json:"id"`
+ VendorID string `json:"vendorId"`
+ TenantID *string `json:"tenantId,omitempty"`
+ Key string `json:"key"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ IsDefault bool `json:"isDefault"`
+ FirstUserRole bool `json:"firstUserRole"`
+ CreatedAt time.Time `json:"createdAt"`
+ UpdatedAt time.Time `json:"updatedAt"`
+ Permissions []string `json:"permissions"`
+ Level int `json:"level"`
+}
+
+// Helper function to construct app password from clientId and secret.
+func ConstructAppPassword(clientID, secret string) string {
+ // Remove dashes and concatenate with "mzp_" prefix.
+ clientIDClean := strings.ReplaceAll(clientID, "-", "")
+ secretClean := strings.ReplaceAll(secret, "-", "")
+ return fmt.Sprintf("mzp_%s%s", clientIDClean, secretClean)
+}
+
+const (
+ AwsUsEast1 Region = "aws/us-east-1"
+ AwsUsWest2 Region = "aws/us-west-2"
+ AwsEuWest1 Region = "aws/eu-west-1"
+)
diff --git a/pkg/clients/helpers_test.go b/pkg/clients/helpers_test.go
new file mode 100644
index 00000000..ff8dc146
--- /dev/null
+++ b/pkg/clients/helpers_test.go
@@ -0,0 +1,44 @@
+package clients
+
+import (
+ "strings"
+ "testing"
+)
+
+// TestConstructAppPassword tests the ConstructAppPassword function.
+func TestConstructAppPassword(t *testing.T) {
+ tests := []struct {
+ name string
+ clientID string
+ secret string
+ wantPrefix string
+ }{
+ {
+ name: "normal IDs without dashes",
+ clientID: "1b2a3c",
+ secret: "4d5e6f",
+ wantPrefix: "mzp_1b2a3c4d5e6f",
+ },
+ {
+ name: "IDs with dashes",
+ clientID: "1b2a-3c4d-5e6f",
+ secret: "7a8b-9c0d-1e2f",
+ wantPrefix: "mzp_1b2a3c4d5e6f7a8b9c0d1e2f",
+ },
+ {
+ name: "long IDs",
+ clientID: "1b2a3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
+ secret: "7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
+ wantPrefix: "mzp_1b2a3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := ConstructAppPassword(tt.clientID, tt.secret)
+ if !strings.HasPrefix(got, tt.wantPrefix) {
+ t.Errorf("ConstructAppPassword() = %v, want prefix %v", got, tt.wantPrefix)
+ }
+ })
+ }
+}
diff --git a/pkg/datasources/datasource_cluster.go b/pkg/datasources/datasource_cluster.go
index 5a610c4c..91bdf823 100644
--- a/pkg/datasources/datasource_cluster.go
+++ b/pkg/datasources/datasource_cluster.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Cluster() *schema.Resource {
@@ -48,6 +47,7 @@ func Cluster() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -55,7 +55,11 @@ func Cluster() *schema.Resource {
func clusterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
- dataSource, err := materialize.ListClusters(meta.(*sqlx.DB))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListClusters(metaDb)
if err != nil {
return diag.FromErr(err)
}
@@ -78,6 +82,6 @@ func clusterRead(ctx context.Context, d *schema.ResourceData, meta interface{})
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion("clusters"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "clusters"))
return diags
}
diff --git a/pkg/datasources/datasource_cluster_replica.go b/pkg/datasources/datasource_cluster_replica.go
index 35384cbb..948cbc39 100644
--- a/pkg/datasources/datasource_cluster_replica.go
+++ b/pkg/datasources/datasource_cluster_replica.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func ClusterReplica() *schema.Resource {
@@ -48,6 +47,7 @@ func ClusterReplica() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -55,7 +55,11 @@ func ClusterReplica() *schema.Resource {
func clusterReplicaRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
- dataSource, err := materialize.ListClusterReplicas(meta.(*sqlx.DB))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListClusterReplicas(metaDb)
if err != nil {
return diag.FromErr(err)
}
@@ -78,6 +82,6 @@ func clusterReplicaRead(ctx context.Context, d *schema.ResourceData, meta interf
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion("cluster_replicas"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "cluster_replicas"))
return diags
}
diff --git a/pkg/datasources/datasource_cluster_replica_test.go b/pkg/datasources/datasource_cluster_replica_test.go
index bec7eb10..64716a0b 100644
--- a/pkg/datasources/datasource_cluster_replica_test.go
+++ b/pkg/datasources/datasource_cluster_replica_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -19,7 +19,7 @@ func TestClusterReplicaDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, ClusterReplica().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
testhelpers.MockClusterReplicaScan(mock, "")
if err := clusterReplicaRead(context.TODO(), d, db); err != nil {
diff --git a/pkg/datasources/datasource_cluster_test.go b/pkg/datasources/datasource_cluster_test.go
index c31a0737..66624681 100644
--- a/pkg/datasources/datasource_cluster_test.go
+++ b/pkg/datasources/datasource_cluster_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -19,7 +19,7 @@ func TestClusterDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Cluster().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
testhelpers.MockClusterScan(mock, "")
if err := clusterRead(context.TODO(), d, db); err != nil {
diff --git a/pkg/datasources/datasource_connection.go b/pkg/datasources/datasource_connection.go
index 41ef4df6..f851f6df 100644
--- a/pkg/datasources/datasource_connection.go
+++ b/pkg/datasources/datasource_connection.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Connection() *schema.Resource {
@@ -54,6 +54,7 @@ func Connection() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -64,7 +65,11 @@ func connectionRead(ctx context.Context, d *schema.ResourceData, meta interface{
var diags diag.Diagnostics
- dataSource, err := materialize.ListConnections(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListConnections(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -86,6 +91,6 @@ func connectionRead(ctx context.Context, d *schema.ResourceData, meta interface{
return diag.FromErr(err)
}
- SetId("connections", databaseName, schemaName, d)
+ SetId(string(region), "connections", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_connection_test.go b/pkg/datasources/datasource_connection_test.go
index 86274262..ea25fe8f 100644
--- a/pkg/datasources/datasource_connection_test.go
+++ b/pkg/datasources/datasource_connection_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestConnectionDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Connection().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockConnectionScan(mock, p)
diff --git a/pkg/datasources/datasource_current_cluster.go b/pkg/datasources/datasource_current_cluster.go
index a25c105a..49821eae 100644
--- a/pkg/datasources/datasource_current_cluster.go
+++ b/pkg/datasources/datasource_current_cluster.go
@@ -6,7 +6,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func CurrentCluster() *schema.Resource {
@@ -17,6 +16,7 @@ func CurrentCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
+ "region": RegionSchema(),
},
}
}
@@ -24,12 +24,16 @@ func CurrentCluster() *schema.Resource {
func currentClusterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
- conn := meta.(*sqlx.DB)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ conn := metaDb
var name string
conn.QueryRow("SHOW CLUSTER;").Scan(&name)
d.Set("name", name)
- d.SetId(utils.TransformIdWithRegion("current_cluster"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "current_cluster"))
return diags
}
diff --git a/pkg/datasources/datasource_current_cluster_test.go b/pkg/datasources/datasource_current_cluster_test.go
index 94342b41..f9e1a149 100644
--- a/pkg/datasources/datasource_current_cluster_test.go
+++ b/pkg/datasources/datasource_current_cluster_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -19,7 +19,7 @@ func TestCurrentClusterDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, CurrentCluster().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
ir := mock.NewRows([]string{"cluster"}).AddRow("quickstart")
mock.ExpectQuery(`SHOW CLUSTER;`).WillReturnRows(ir)
diff --git a/pkg/datasources/datasource_current_database.go b/pkg/datasources/datasource_current_database.go
index 9f53d01a..70d88dd2 100644
--- a/pkg/datasources/datasource_current_database.go
+++ b/pkg/datasources/datasource_current_database.go
@@ -6,7 +6,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func CurrentDatabase() *schema.Resource {
@@ -17,6 +16,7 @@ func CurrentDatabase() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
+ "region": RegionSchema(),
},
}
}
@@ -24,12 +24,16 @@ func CurrentDatabase() *schema.Resource {
func currentDatabaseRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
- conn := meta.(*sqlx.DB)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ conn := metaDb
var name string
conn.QueryRow("SHOW DATABASE;").Scan(&name)
d.Set("name", name)
- d.SetId(utils.TransformIdWithRegion("current_database"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "current_database"))
return diags
}
diff --git a/pkg/datasources/datasource_current_database_test.go b/pkg/datasources/datasource_current_database_test.go
index e04d9be4..ecc0df1f 100644
--- a/pkg/datasources/datasource_current_database_test.go
+++ b/pkg/datasources/datasource_current_database_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -19,7 +19,7 @@ func TestCurrentDatabaseDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, CurrentDatabase().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
ir := mock.NewRows([]string{"database"}).AddRow("materialize")
mock.ExpectQuery(`SHOW DATABASE;`).WillReturnRows(ir)
diff --git a/pkg/datasources/datasource_database.go b/pkg/datasources/datasource_database.go
index 343854ae..cbbd9ebb 100644
--- a/pkg/datasources/datasource_database.go
+++ b/pkg/datasources/datasource_database.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Database() *schema.Resource {
@@ -32,6 +31,7 @@ func Database() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -39,7 +39,12 @@ func Database() *schema.Resource {
func databaseRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
- dataSource, err := materialize.ListDatabases(meta.(*sqlx.DB))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ dataSource, err := materialize.ListDatabases(metaDb)
if err != nil {
return diag.FromErr(err)
}
@@ -58,6 +63,6 @@ func databaseRead(ctx context.Context, d *schema.ResourceData, meta interface{})
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion("databases"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "databases"))
return diags
}
diff --git a/pkg/datasources/datasource_database_test.go b/pkg/datasources/datasource_database_test.go
index 40438779..05e72357 100644
--- a/pkg/datasources/datasource_database_test.go
+++ b/pkg/datasources/datasource_database_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -19,7 +19,7 @@ func TestDatabaseDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Database().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
testhelpers.MockDatabaseScan(mock, "")
if err := databaseRead(context.TODO(), d, db); err != nil {
diff --git a/pkg/datasources/datasource_egress_ips.go b/pkg/datasources/datasource_egress_ips.go
index eba3db4b..ca813e9c 100644
--- a/pkg/datasources/datasource_egress_ips.go
+++ b/pkg/datasources/datasource_egress_ips.go
@@ -10,7 +10,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func EgressIps() *schema.Resource {
@@ -23,6 +22,7 @@ func EgressIps() *schema.Resource {
Description: "The egress IPs in the account",
Elem: &schema.Schema{Type: schema.TypeString},
},
+ "region": RegionSchema(),
},
}
}
@@ -30,7 +30,11 @@ func EgressIps() *schema.Resource {
func EgressIpsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
- conn := meta.(*sqlx.DB)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ conn := metaDb
q := materialize.ReadEgressIpsDatasource()
@@ -65,7 +69,7 @@ func EgressIpsRead(ctx context.Context, d *schema.ResourceData, meta interface{}
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion("egress_ips"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "egress_ips"))
return diags
}
diff --git a/pkg/datasources/datasource_egress_ips_test.go b/pkg/datasources/datasource_egress_ips_test.go
index e61af701..08c07c5c 100644
--- a/pkg/datasources/datasource_egress_ips_test.go
+++ b/pkg/datasources/datasource_egress_ips_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -19,7 +19,7 @@ func TestEgressIpsDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, EgressIps().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
ir := mock.NewRows([]string{"egress_ip"}).
AddRow("egress_ip")
mock.ExpectQuery(`SELECT egress_ip FROM materialize.mz_catalog.mz_egress_ips;`).WillReturnRows(ir)
diff --git a/pkg/datasources/datasource_index.go b/pkg/datasources/datasource_index.go
index 81ec8a8b..7f2e05b2 100644
--- a/pkg/datasources/datasource_index.go
+++ b/pkg/datasources/datasource_index.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Index() *schema.Resource {
@@ -54,6 +54,7 @@ func Index() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -64,7 +65,11 @@ func indexRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
var diags diag.Diagnostics
- dataSource, err := materialize.ListIndexes(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListIndexes(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -86,6 +91,6 @@ func indexRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
return diag.FromErr(err)
}
- SetId("indexes", databaseName, schemaName, d)
+ SetId(string(region), "indexes", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_index_test.go b/pkg/datasources/datasource_index_test.go
index fdf6bd9e..1a713181 100644
--- a/pkg/datasources/datasource_index_test.go
+++ b/pkg/datasources/datasource_index_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestIndexDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Index().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `
WHERE mz_databases.name = 'database'
AND mz_objects.type IN \('source', 'view', 'materialized-view'\)
diff --git a/pkg/datasources/datasource_materialized_view.go b/pkg/datasources/datasource_materialized_view.go
index b6963b81..d74b642a 100644
--- a/pkg/datasources/datasource_materialized_view.go
+++ b/pkg/datasources/datasource_materialized_view.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func MaterializedView() *schema.Resource {
@@ -50,6 +50,7 @@ func MaterializedView() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -60,7 +61,11 @@ func materializedViewRead(ctx context.Context, d *schema.ResourceData, meta inte
var diags diag.Diagnostics
- dataSource, err := materialize.ListMaterializedViews(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListMaterializedViews(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -81,6 +86,6 @@ func materializedViewRead(ctx context.Context, d *schema.ResourceData, meta inte
return diag.FromErr(err)
}
- SetId("materialized_views", databaseName, schemaName, d)
+ SetId(string(region), "materialized_views", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_materialized_view_test.go b/pkg/datasources/datasource_materialized_view_test.go
index 7650e6d5..8a2f325d 100644
--- a/pkg/datasources/datasource_materialized_view_test.go
+++ b/pkg/datasources/datasource_materialized_view_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestMaterializedViewDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, MaterializedView().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockMaterializeViewScan(mock, p)
diff --git a/pkg/datasources/datasource_region.go b/pkg/datasources/datasource_region.go
new file mode 100644
index 00000000..a3b57a82
--- /dev/null
+++ b/pkg/datasources/datasource_region.go
@@ -0,0 +1,99 @@
+package datasources
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "strings"
+
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func Region() *schema.Resource {
+ return &schema.Resource{
+ ReadContext: RegionRead,
+ Schema: map[string]*schema.Schema{
+ "regions": {
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The name of the region.",
+ },
+ "url": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The URL at which the Region API can be reached.",
+ },
+ "cloud_provider": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The cloud provider of the region. Currently, only AWS is supported.",
+ },
+ "host": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The SQL host of the region. This is the hostname of the Materialize cluster in the region.",
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func RegionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ providerMeta, err := utils.GetProviderMeta(meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ client := providerMeta.CloudAPI
+
+ providers, err := client.ListCloudProviders(ctx)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ var regions []map[string]interface{}
+ for _, provider := range providers {
+ host, err := client.GetHost(ctx, provider.ID)
+ if err != nil {
+ if strings.Contains(err.Error(), "non-200 status code: 204") {
+ log.Printf("[WARN] No host available for region %s, skipping", provider.ID)
+ continue
+ }
+ return diag.FromErr(fmt.Errorf("error fetching host for region %s: %s", provider.ID, err))
+ }
+
+ region := createRegionMap(provider, host)
+ regions = append(regions, region)
+ }
+
+ if err := d.Set("regions", regions); err != nil {
+ return diag.FromErr(err)
+ }
+
+ d.SetId("regions")
+ return nil
+}
+
+// createRegionMap creates a map of region details
+func createRegionMap(provider clients.CloudProvider, host string) map[string]interface{} {
+ return map[string]interface{}{
+ "id": provider.ID,
+ "name": provider.Name,
+ "url": provider.Url,
+ "cloud_provider": provider.CloudProvider,
+ "host": host,
+ }
+}
diff --git a/pkg/datasources/datasource_region_test.go b/pkg/datasources/datasource_region_test.go
new file mode 100644
index 00000000..a76dc9f3
--- /dev/null
+++ b/pkg/datasources/datasource_region_test.go
@@ -0,0 +1,64 @@
+package datasources
+
+import (
+ "context"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/stretchr/testify/require"
+)
+
+func TestRegionRead(t *testing.T) {
+ r := require.New(t)
+
+ // Set up the mock cloud server
+ testhelpers.WithMockCloudServer(t, func(serverURL string) {
+ // Create an http.Client that uses the mock transport
+ mockClient := &http.Client{
+ Transport: &testhelpers.MockCloudService{},
+ }
+
+ fronteggClient := &clients.FronteggClient{
+ Endpoint: serverURL,
+ HTTPClient: mockClient,
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ }
+ // Create a mock cloud client
+ mockCloudClient := &clients.CloudAPIClient{
+ FronteggClient: fronteggClient,
+ Endpoint: serverURL,
+ }
+
+ // Create a provider meta with the mock cloud client
+ providerMeta := &utils.ProviderMeta{
+ CloudAPI: mockCloudClient,
+ Frontegg: fronteggClient,
+ }
+
+ // Create a test resource data with the Region schema
+ d := schema.TestResourceDataRaw(t, Region().Schema, nil)
+ d.SetId("regions")
+
+ // Call the RegionRead function
+ diags := RegionRead(context.TODO(), d, providerMeta)
+
+ // Print error messages in diagnostics
+ for _, diag := range diags {
+ t.Logf("Error: %s", diag.Summary)
+ t.Logf("Details: %s", diag.Detail)
+ }
+
+ // Check for errors within the diagnostics
+ r.False(diags.HasError())
+ r.Equal("aws/us-east-1", d.Get("regions.0.id"))
+ r.Equal("us-east-1", d.Get("regions.0.name"))
+ r.Equal("http://mockendpoint", d.Get("regions.0.url"))
+ r.Equal("aws", d.Get("regions.0.cloud_provider"))
+ r.Equal("sql.materialize.com", d.Get("regions.0.host"))
+ })
+}
diff --git a/pkg/datasources/datasource_role.go b/pkg/datasources/datasource_role.go
index ac829671..3e3f5365 100644
--- a/pkg/datasources/datasource_role.go
+++ b/pkg/datasources/datasource_role.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Role() *schema.Resource {
@@ -32,6 +31,7 @@ func Role() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -39,7 +39,11 @@ func Role() *schema.Resource {
func roleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
- dataSource, err := materialize.ListRoles(meta.(*sqlx.DB))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListRoles(metaDb)
if err != nil {
return diag.FromErr(err)
}
@@ -58,6 +62,6 @@ func roleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion("roles"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "roles"))
return diags
}
diff --git a/pkg/datasources/datasource_role_test.go b/pkg/datasources/datasource_role_test.go
index 65557c13..2c7371e2 100644
--- a/pkg/datasources/datasource_role_test.go
+++ b/pkg/datasources/datasource_role_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -19,7 +19,7 @@ func TestRoleDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Role().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
testhelpers.MockRoleScan(mock, "")
if err := roleRead(context.TODO(), d, db); err != nil {
diff --git a/pkg/datasources/datasource_schema.go b/pkg/datasources/datasource_schema.go
index e80ccdad..290716f4 100644
--- a/pkg/datasources/datasource_schema.go
+++ b/pkg/datasources/datasource_schema.go
@@ -9,7 +9,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Schema() *schema.Resource {
@@ -42,6 +41,7 @@ func Schema() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -51,7 +51,11 @@ func schemaRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
var diags diag.Diagnostics
- dataSource, err := materialize.ListSchemas(meta.(*sqlx.DB), databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListSchemas(metaDb, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -73,9 +77,9 @@ func schemaRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
if databaseName != "" {
id := fmt.Sprintf("%s|schemas", databaseName)
- d.SetId(utils.TransformIdWithRegion(id))
+ d.SetId(utils.TransformIdWithRegion(string(region), id))
} else {
- d.SetId(utils.TransformIdWithRegion("schemas"))
+ d.SetId(utils.TransformIdWithRegion(string(region), "schemas"))
}
return diags
diff --git a/pkg/datasources/datasource_schema_test.go b/pkg/datasources/datasource_schema_test.go
index a2a4eb73..7bad1d9d 100644
--- a/pkg/datasources/datasource_schema_test.go
+++ b/pkg/datasources/datasource_schema_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -21,7 +21,7 @@ func TestSchemaDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Schema().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database'`
testhelpers.MockSchemaScan(mock, p)
diff --git a/pkg/datasources/datasource_secret.go b/pkg/datasources/datasource_secret.go
index 298c01c6..119be621 100644
--- a/pkg/datasources/datasource_secret.go
+++ b/pkg/datasources/datasource_secret.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Secret() *schema.Resource {
@@ -50,6 +50,7 @@ func Secret() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -60,7 +61,11 @@ func secretRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
var diags diag.Diagnostics
- dataSource, err := materialize.ListSecrets(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListSecrets(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -81,6 +86,6 @@ func secretRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
return diag.FromErr(err)
}
- SetId("secrets", databaseName, schemaName, d)
+ SetId(string(region), "secrets", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_secret_test.go b/pkg/datasources/datasource_secret_test.go
index c4f78485..d6977b23 100644
--- a/pkg/datasources/datasource_secret_test.go
+++ b/pkg/datasources/datasource_secret_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestSecretDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Secret().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockSecretScan(mock, p)
diff --git a/pkg/datasources/datasource_sink.go b/pkg/datasources/datasource_sink.go
index fb0e5b63..472396da 100644
--- a/pkg/datasources/datasource_sink.go
+++ b/pkg/datasources/datasource_sink.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Sink() *schema.Resource {
@@ -70,6 +70,7 @@ func Sink() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -80,7 +81,11 @@ func sinkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
var diags diag.Diagnostics
- dataSource, err := materialize.ListSinks(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListSinks(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -106,7 +111,7 @@ func sinkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- SetId("sinks", databaseName, schemaName, d)
+ SetId(string(region), "sinks", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_sink_test.go b/pkg/datasources/datasource_sink_test.go
index 5e3a7237..d4372450 100644
--- a/pkg/datasources/datasource_sink_test.go
+++ b/pkg/datasources/datasource_sink_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestSinkDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Sink().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockSinkScan(mock, p)
diff --git a/pkg/datasources/datasource_source.go b/pkg/datasources/datasource_source.go
index 8a2955bc..ccfb0d08 100644
--- a/pkg/datasources/datasource_source.go
+++ b/pkg/datasources/datasource_source.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Source() *schema.Resource {
@@ -70,6 +70,7 @@ func Source() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -80,7 +81,11 @@ func sourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
var diags diag.Diagnostics
- dataSource, err := materialize.ListSources(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListSources(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -106,7 +111,7 @@ func sourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
return diag.FromErr(err)
}
- SetId("sources", databaseName, schemaName, d)
+ SetId(string(region), "sources", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_source_test.go b/pkg/datasources/datasource_source_test.go
index 481ac1e4..d4845608 100644
--- a/pkg/datasources/datasource_source_test.go
+++ b/pkg/datasources/datasource_source_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestSourceDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Source().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockSourceScan(mock, p)
diff --git a/pkg/datasources/datasource_table.go b/pkg/datasources/datasource_table.go
index da2b7d10..699ab894 100644
--- a/pkg/datasources/datasource_table.go
+++ b/pkg/datasources/datasource_table.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Table() *schema.Resource {
@@ -50,6 +50,7 @@ func Table() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -60,7 +61,11 @@ func tableRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
var diags diag.Diagnostics
- dataSource, err := materialize.ListTables(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListTables(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -81,7 +86,7 @@ func tableRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
return diag.FromErr(err)
}
- SetId("tables", databaseName, schemaName, d)
+ SetId(string(region), "tables", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_table_test.go b/pkg/datasources/datasource_table_test.go
index 19c8b15f..2997a8aa 100644
--- a/pkg/datasources/datasource_table_test.go
+++ b/pkg/datasources/datasource_table_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestTableDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Table().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockTableScan(mock, p)
diff --git a/pkg/datasources/datasource_type.go b/pkg/datasources/datasource_type.go
index dc420d43..2483eb6d 100644
--- a/pkg/datasources/datasource_type.go
+++ b/pkg/datasources/datasource_type.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func Type() *schema.Resource {
@@ -54,6 +54,7 @@ func Type() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -64,7 +65,11 @@ func typeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
var diags diag.Diagnostics
- dataSource, err := materialize.ListTypes(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListTypes(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -86,7 +91,7 @@ func typeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- SetId("types", databaseName, schemaName, d)
+ SetId(string(region), "types", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_type_test.go b/pkg/datasources/datasource_type_test.go
index 8f3aa008..23b8fb7a 100644
--- a/pkg/datasources/datasource_type_test.go
+++ b/pkg/datasources/datasource_type_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestTypesDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, Type().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockTypeScan(mock, p)
diff --git a/pkg/datasources/datasource_view.go b/pkg/datasources/datasource_view.go
index 722fe5a9..a42d7901 100644
--- a/pkg/datasources/datasource_view.go
+++ b/pkg/datasources/datasource_view.go
@@ -4,10 +4,10 @@ import (
"context"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func View() *schema.Resource {
@@ -50,6 +50,7 @@ func View() *schema.Resource {
},
},
},
+ "region": RegionSchema(),
},
}
}
@@ -60,7 +61,11 @@ func viewRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
var diags diag.Diagnostics
- dataSource, err := materialize.ListViews(meta.(*sqlx.DB), schemaName, databaseName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ dataSource, err := materialize.ListViews(metaDb, schemaName, databaseName)
if err != nil {
return diag.FromErr(err)
}
@@ -81,7 +86,7 @@ func viewRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- SetId("views", databaseName, schemaName, d)
+ SetId(string(region), "views", databaseName, schemaName, d)
return diags
}
diff --git a/pkg/datasources/datasource_view_test.go b/pkg/datasources/datasource_view_test.go
index 90d3ea46..f781b315 100644
--- a/pkg/datasources/datasource_view_test.go
+++ b/pkg/datasources/datasource_view_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestViewDatasource(t *testing.T) {
d := schema.TestResourceDataRaw(t, View().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
p := `WHERE mz_databases.name = 'database' AND mz_schemas.name = 'schema'`
testhelpers.MockViewScan(mock, p)
diff --git a/pkg/datasources/utils.go b/pkg/datasources/utils.go
index 7c2b391a..000767bc 100644
--- a/pkg/datasources/utils.go
+++ b/pkg/datasources/utils.go
@@ -7,7 +7,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
-func SetId(resource, databaseName, schemaName string, d *schema.ResourceData) {
+func SetId(region, resource, databaseName, schemaName string, d *schema.ResourceData) {
var id string
if databaseName != "" && schemaName != "" {
id = fmt.Sprintf("%s|%s|%s", databaseName, schemaName, resource)
@@ -17,5 +17,13 @@ func SetId(resource, databaseName, schemaName string, d *schema.ResourceData) {
id = resource
}
- d.SetId(utils.TransformIdWithRegion(id))
+ d.SetId(utils.TransformIdWithRegion(region, id))
+}
+
+func RegionSchema() *schema.Schema {
+ return &schema.Schema{
+ Description: "The region in which the resource is located.",
+ Type: schema.TypeString,
+ Computed: true,
+ }
}
diff --git a/pkg/materialize/cluster_replica.go b/pkg/materialize/cluster_replica.go
index 19dc645f..3805bd09 100644
--- a/pkg/materialize/cluster_replica.go
+++ b/pkg/materialize/cluster_replica.go
@@ -74,7 +74,7 @@ func (b *ClusterReplicaBuilder) Create() error {
}
if b.disk {
- i := fmt.Sprintf(` DISK`)
+ i := " DISK"
p = append(p, i)
}
diff --git a/pkg/provider/acceptance_cluster_replica_test.go b/pkg/provider/acceptance_cluster_replica_test.go
index 9d37dc13..34f0d206 100644
--- a/pkg/provider/acceptance_cluster_replica_test.go
+++ b/pkg/provider/acceptance_cluster_replica_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccClusterReplica_basic(t *testing.T) {
@@ -133,18 +132,26 @@ func testAccClusterReplicaWithComment(clusterName, clusterReplica, comment strin
func testAccCheckClusterReplicaExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("cluster replica not found: %s", name)
}
- _, err := materialize.ScanClusterReplica(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanClusterReplica(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllClusterReplicaDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_cluster_replica" {
diff --git a/pkg/provider/acceptance_cluster_test.go b/pkg/provider/acceptance_cluster_test.go
index 80829ce1..a1e1a1c8 100644
--- a/pkg/provider/acceptance_cluster_test.go
+++ b/pkg/provider/acceptance_cluster_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccCluster_basic(t *testing.T) {
@@ -372,18 +371,26 @@ func testAccClusterManagedResource(
func testAccCheckClusterExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("cluster not found: %s", name)
}
- _, err := materialize.ScanCluster(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanCluster(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllClusterDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_cluster" {
diff --git a/pkg/provider/acceptance_connection_confluent_schema_registry_test.go b/pkg/provider/acceptance_connection_confluent_schema_registry_test.go
index 6ab80c82..a1665009 100644
--- a/pkg/provider/acceptance_connection_confluent_schema_registry_test.go
+++ b/pkg/provider/acceptance_connection_confluent_schema_registry_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccConnConfluentSchemaRegistry_basic(t *testing.T) {
@@ -126,18 +125,26 @@ resource "materialize_connection_confluent_schema_registry" "test_role" {
func testAccCheckConnConfluentSchemaRegistryExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("connection confluent schema registry not found: %s", name)
}
- _, err := materialize.ScanConnection(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanConnection(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllConnConfluentSchemaRegistryDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_connection_confluent_schema_registry" {
diff --git a/pkg/provider/acceptance_connection_kafka_test.go b/pkg/provider/acceptance_connection_kafka_test.go
index 5e099dfc..857cb30d 100644
--- a/pkg/provider/acceptance_connection_kafka_test.go
+++ b/pkg/provider/acceptance_connection_kafka_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccConnKafka_basic(t *testing.T) {
@@ -264,18 +263,26 @@ func testAccConnKafkaSshResource(connectionName string) string {
func testAccCheckConnKafkaExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("connection kafka not found: %s", name)
}
- _, err := materialize.ScanConnection(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanConnection(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllConnKafkaDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_connection_kafka" {
diff --git a/pkg/provider/acceptance_connection_postgres_test.go b/pkg/provider/acceptance_connection_postgres_test.go
index 1d38e3bc..419a1c59 100644
--- a/pkg/provider/acceptance_connection_postgres_test.go
+++ b/pkg/provider/acceptance_connection_postgres_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccConnPostgres_basic(t *testing.T) {
@@ -162,18 +161,26 @@ resource "materialize_connection_postgres" "test_role" {
func testAccCheckConnPostgresExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("connection postgres not found: %s", name)
}
- _, err := materialize.ScanConnection(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanConnection(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllConnPostgresDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_connection_postgres" {
diff --git a/pkg/provider/acceptance_connection_ssh_tunnel_test.go b/pkg/provider/acceptance_connection_ssh_tunnel_test.go
index 64fa0678..6de0d5d8 100644
--- a/pkg/provider/acceptance_connection_ssh_tunnel_test.go
+++ b/pkg/provider/acceptance_connection_ssh_tunnel_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccConnSshTunnel_basic(t *testing.T) {
@@ -136,18 +135,26 @@ resource "materialize_connection_ssh_tunnel" "test_role" {
func testAccCheckConnSshTunnelExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("connection ssh tunnel not found: %s", name)
}
- _, err := materialize.ScanConnectionSshTunnel(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanConnectionSshTunnel(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllConnSshTunnelDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_connection_ssh_tunnel" {
diff --git a/pkg/provider/acceptance_database_test.go b/pkg/provider/acceptance_database_test.go
index 50b5449c..0e686607 100644
--- a/pkg/provider/acceptance_database_test.go
+++ b/pkg/provider/acceptance_database_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccDatabase_basic(t *testing.T) {
@@ -130,18 +129,26 @@ func testAccDatabaseResource(roleName, databaseName, databse2Name, databaseOwner
func testAccCheckDatabaseExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("database not found: %s", name)
}
- _, err := materialize.ScanDatabase(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanDatabase(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllDatabasesDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_database" {
diff --git a/pkg/provider/acceptance_grant_system_privilege_test.go b/pkg/provider/acceptance_grant_system_privilege_test.go
index d1cb5967..addc074b 100644
--- a/pkg/provider/acceptance_grant_system_privilege_test.go
+++ b/pkg/provider/acceptance_grant_system_privilege_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccGrantSystemPrivilege_basic(t *testing.T) {
@@ -71,7 +71,11 @@ resource "materialize_grant_system_privilege" "test" {
func testAccCheckGrantSystemPrivilegeExists(grantName, roleName, privilege string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
_, ok := s.RootModule().Resources[grantName]
if !ok {
return fmt.Errorf("grant not found")
@@ -82,7 +86,7 @@ func testAccCheckGrantSystemPrivilegeExists(grantName, roleName, privilege strin
// return err
// }
- _, err := materialize.ScanSystemPrivileges(db)
+ _, err = materialize.ScanSystemPrivileges(db)
if err != nil {
return err
}
@@ -93,8 +97,12 @@ func testAccCheckGrantSystemPrivilegeExists(grantName, roleName, privilege strin
func testAccCheckGrantSystemPrivilegeRevoked(roleName, privilege string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`REVOKE %[1]s ON SYSTEM FROM %[2]s;`, roleName, privilege))
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`REVOKE %[1]s ON SYSTEM FROM %[2]s;`, roleName, privilege))
return err
}
}
diff --git a/pkg/provider/acceptance_index_test.go b/pkg/provider/acceptance_index_test.go
index bdc96079..51493a14 100644
--- a/pkg/provider/acceptance_index_test.go
+++ b/pkg/provider/acceptance_index_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccIndex_basic(t *testing.T) {
@@ -156,26 +155,38 @@ func testAccIndexWithComment(viewName, indexName, comment string) string {
func testAccCheckIndexExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("index not found: %s", name)
}
- _, err := materialize.ScanIndex(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanIndex(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckIndexDisappears(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`DROP INDEX "%s" RESTRICT;`, name))
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`DROP INDEX "%s" RESTRICT;`, name))
return err
}
}
func testAccCheckAllIndexDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_index" {
diff --git a/pkg/provider/acceptance_materialized_view_test.go b/pkg/provider/acceptance_materialized_view_test.go
index 5cff2015..30edf652 100644
--- a/pkg/provider/acceptance_materialized_view_test.go
+++ b/pkg/provider/acceptance_materialized_view_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccMaterializedView_basic(t *testing.T) {
@@ -140,18 +139,26 @@ func testAccMaterializedViewResource(roleName, materializeViewName, materializeV
func testAccCheckMaterializedViewExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Materialized View not found: %s", name)
}
- _, err := materialize.ScanMaterializedView(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanMaterializedView(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllMaterializedViewsDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_materialized_view" {
diff --git a/pkg/provider/acceptance_role_grant_test.go b/pkg/provider/acceptance_role_grant_test.go
index f6eaa920..f084cdee 100644
--- a/pkg/provider/acceptance_role_grant_test.go
+++ b/pkg/provider/acceptance_role_grant_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccGrantRole_basic(t *testing.T) {
@@ -85,7 +85,11 @@ resource "materialize_role_grant" "test" {
func testAccCheckGrantRoleExists(grantName, roleName, granteeName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
_, ok := s.RootModule().Resources[grantName]
if !ok {
return fmt.Errorf("grant not found")
@@ -112,8 +116,12 @@ func testAccCheckGrantRoleExists(grantName, roleName, granteeName string) resour
func testAccCheckGrantRoleRevoked(roleName, granteeName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`REVOKE %[1]s FROM %[2]s;`, roleName, granteeName))
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`REVOKE %[1]s FROM %[2]s;`, roleName, granteeName))
return err
}
}
diff --git a/pkg/provider/acceptance_role_test.go b/pkg/provider/acceptance_role_test.go
index 3041b039..ed781e22 100644
--- a/pkg/provider/acceptance_role_test.go
+++ b/pkg/provider/acceptance_role_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccRole_basic(t *testing.T) {
@@ -107,18 +106,26 @@ resource "materialize_role" "test" {
func testAccCheckRoleExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("role not found: %s", name)
}
- _, err := materialize.ScanRole(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanRole(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllRolesDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_role" {
diff --git a/pkg/provider/acceptance_schema_test.go b/pkg/provider/acceptance_schema_test.go
index 5271a460..b9b15e90 100644
--- a/pkg/provider/acceptance_schema_test.go
+++ b/pkg/provider/acceptance_schema_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccSchema_basic(t *testing.T) {
@@ -129,25 +128,33 @@ func testAccSchemaResource(roleName, schemaName, schema2Name, schemaOwner, comme
func testAccCheckSchemaExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Schema not found: %s", name)
}
- _, err := materialize.ScanSchema(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSchema(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllSchemasDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_schema" {
continue
}
- _, err := materialize.ScanSchema(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSchema(db, utils.ExtractId(r.Primary.ID))
if err == nil {
return fmt.Errorf("Schema %v still exists", utils.ExtractId(r.Primary.ID))
} else if err != sql.ErrNoRows {
diff --git a/pkg/provider/acceptance_secret_test.go b/pkg/provider/acceptance_secret_test.go
index deefe202..8f214126 100644
--- a/pkg/provider/acceptance_secret_test.go
+++ b/pkg/provider/acceptance_secret_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccSecret_basic(t *testing.T) {
@@ -137,18 +136,26 @@ func testAccSecretResource(roleName, secretName, secretValue, secret2Name, secre
func testAccCheckSecretExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("secret not found: %s", name)
}
- _, err := materialize.ScanSecret(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSecret(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllSecretsDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_secret" {
diff --git a/pkg/provider/acceptance_sink_kafka_test.go b/pkg/provider/acceptance_sink_kafka_test.go
index a5f2a213..29bba666 100644
--- a/pkg/provider/acceptance_sink_kafka_test.go
+++ b/pkg/provider/acceptance_sink_kafka_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccSinkKafka_basic(t *testing.T) {
@@ -336,26 +335,38 @@ func testAccSinkKafkaAvroResource(sinkName string) string {
func testAccCheckSinkKafkaExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("sink kafka not found: %s", name)
}
- _, err := materialize.ScanSink(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSink(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckSinkKafkaDisappears(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`DROP SINK "%s";`, name))
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`DROP SINK "%s";`, name))
return err
}
}
func testAccCheckAllSinkKafkaDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_sink_kafka" {
diff --git a/pkg/provider/acceptance_source_kafka_test.go b/pkg/provider/acceptance_source_kafka_test.go
index 3ba42191..3d4845ae 100644
--- a/pkg/provider/acceptance_source_kafka_test.go
+++ b/pkg/provider/acceptance_source_kafka_test.go
@@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
// Initialize a topic used by Kafka Testacc against the docker compose
@@ -333,18 +332,26 @@ func testAccSourceKafkaResourceAvro(sourceName string) string {
func testAccCheckSourceKafkaExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("source kafka not found: %s", name)
}
- _, err := materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllSourceKafkaDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_source_kafka" {
diff --git a/pkg/provider/acceptance_source_load_generator_test.go b/pkg/provider/acceptance_source_load_generator_test.go
index a05de269..be11e835 100644
--- a/pkg/provider/acceptance_source_load_generator_test.go
+++ b/pkg/provider/acceptance_source_load_generator_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccSourceLoadGeneratorCounter_basic(t *testing.T) {
@@ -313,26 +312,38 @@ func testAccSourceLoadGeneratorTPCHResource(sourceName string) string {
func testAccCheckSourceLoadGeneratorExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("SourceLoadGenerator not found: %s", name)
}
- _, err := materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckSourceLoadGeneratorDisappears(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`DROP SOURCE "%s";`, name))
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`DROP SOURCE "%s";`, name))
return err
}
}
func testAccCheckAllSourceLoadGeneratorsDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_source_load_generator" {
diff --git a/pkg/provider/acceptance_source_postgres_test.go b/pkg/provider/acceptance_source_postgres_test.go
index 8994c53c..eda4c933 100644
--- a/pkg/provider/acceptance_source_postgres_test.go
+++ b/pkg/provider/acceptance_source_postgres_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccSourcePostgres_basic(t *testing.T) {
@@ -416,18 +415,26 @@ func testAccSourcePostgresResourceSchema(sourceName string) string {
func testAccCheckSourcePostgresExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("source postgres not found: %s", name)
}
- _, err := materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllSourcePostgresDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_source_postgres" {
diff --git a/pkg/provider/acceptance_source_webhook_test.go b/pkg/provider/acceptance_source_webhook_test.go
index 2c44867b..59edbbc7 100644
--- a/pkg/provider/acceptance_source_webhook_test.go
+++ b/pkg/provider/acceptance_source_webhook_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccSourceWebhook_basic(t *testing.T) {
@@ -336,18 +335,26 @@ func testAccSourceWebhookRudderstackResource(sourceName string) string {
func testAccCheckSourceWebhookExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("source webhook not found: %s", name)
}
- _, err := materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanSource(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllSourceWebhookDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_source_webhook" {
diff --git a/pkg/provider/acceptance_table_test.go b/pkg/provider/acceptance_table_test.go
index 2aee214c..9c064db2 100644
--- a/pkg/provider/acceptance_table_test.go
+++ b/pkg/provider/acceptance_table_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccTable_basic(t *testing.T) {
@@ -220,18 +219,26 @@ func testAccTableResource(roleName, tableName, tableRoleName, tableOwnership, co
func testAccCheckTableExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Table not found: %s", name)
}
- _, err := materialize.ScanTable(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanTable(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllTablesDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_table" {
diff --git a/pkg/provider/acceptance_type_test.go b/pkg/provider/acceptance_type_test.go
index c3460f17..f033d34f 100644
--- a/pkg/provider/acceptance_type_test.go
+++ b/pkg/provider/acceptance_type_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccTypeList_basic(t *testing.T) {
@@ -225,18 +224,26 @@ func testAccTypeMapResource(typeName string) string {
func testAccCheckTypeExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Type not found: %s", name)
}
- _, err := materialize.ScanType(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanType(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllTypesDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_type" {
diff --git a/pkg/provider/acceptance_view_test.go b/pkg/provider/acceptance_view_test.go
index 2a59293b..61195ff4 100644
--- a/pkg/provider/acceptance_view_test.go
+++ b/pkg/provider/acceptance_view_test.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
)
func TestAccView_basic(t *testing.T) {
@@ -139,18 +138,26 @@ func testAccViewResource(roleName, viewName, view2Name, viewOwner, comment strin
func testAccCheckViewExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
r, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("View not found: %s", name)
}
- _, err := materialize.ScanView(db, utils.ExtractId(r.Primary.ID))
+ _, err = materialize.ScanView(db, utils.ExtractId(r.Primary.ID))
return err
}
}
func testAccCheckAllViewsDestroyed(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
for _, r := range s.RootModule().Resources {
if r.Type != "materialize_view" {
diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go
index 3ebaf258..9f36eefe 100644
--- a/pkg/provider/provider.go
+++ b/pkg/provider/provider.go
@@ -3,8 +3,9 @@ package provider
import (
"context"
"fmt"
- "net/url"
+ "log"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/datasources"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/resources"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
@@ -12,24 +13,11 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
_ "github.com/jackc/pgx/stdlib"
- "github.com/jmoiron/sqlx"
)
func Provider(version string) *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
- "host": {
- Type: schema.TypeString,
- Optional: true,
- Description: "Materialize host. Can also come from the `MZ_HOST` environment variable.",
- DefaultFunc: schema.EnvDefaultFunc("MZ_HOST", nil),
- },
- "user": {
- Type: schema.TypeString,
- Optional: true,
- Description: "Materialize user. Can also come from the `MZ_USER` environment variable.",
- DefaultFunc: schema.EnvDefaultFunc("MZ_USER", nil),
- },
"password": {
Type: schema.TypeString,
Optional: true,
@@ -37,12 +25,6 @@ func Provider(version string) *schema.Provider {
Description: "Materialize host. Can also come from the `MZ_PASSWORD` environment variable.",
DefaultFunc: schema.EnvDefaultFunc("MZ_PASSWORD", nil),
},
- "port": {
- Type: schema.TypeInt,
- Optional: true,
- Description: "The Materialize port number to connect to at the server host. Can also come from the `MZ_PORT` environment variable. Defaults to 6875.",
- DefaultFunc: schema.EnvDefaultFunc("MZ_PORT", 6875),
- },
"database": {
Type: schema.TypeString,
Optional: true,
@@ -55,8 +37,28 @@ func Provider(version string) *schema.Provider {
DefaultFunc: schema.EnvDefaultFunc("MZ_SSLMODE", "require"),
Description: "For testing purposes, the SSL mode to use.",
},
+ "endpoint": {
+ Type: schema.TypeString,
+ Optional: true,
+ DefaultFunc: schema.EnvDefaultFunc("MZ_ENDPOINT", "https://admin.cloud.materialize.com"),
+ Description: "The endpoint for the Materialize API.",
+ },
+ "cloud_endpoint": {
+ Type: schema.TypeString,
+ Optional: true,
+ DefaultFunc: schema.EnvDefaultFunc("MZ_CLOUD_ENDPOINT", "https://api.cloud.materialize.com"),
+ Description: "The endpoint for the Materialize Cloud API.",
+ },
+ "default_region": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: "The default region if not specified in the resource",
+ DefaultFunc: schema.EnvDefaultFunc("MZ_DEFAULT_REGION", "aws/us-east-1"),
+ },
},
ResourcesMap: map[string]*schema.Resource{
+ "materialize_app_password": resources.AppPassword(),
+ "materialize_user": resources.User(),
"materialize_cluster": resources.Cluster(),
"materialize_cluster_grant": resources.GrantCluster(),
"materialize_cluster_grant_default_privilege": resources.GrantClusterDefaultPrivilege(),
@@ -108,6 +110,7 @@ func Provider(version string) *schema.Provider {
"materialize_egress_ips": datasources.EgressIps(),
"materialize_index": datasources.Index(),
"materialize_materialized_view": datasources.MaterializedView(),
+ "materialize_region": datasources.Region(),
"materialize_role": datasources.Role(),
"materialize_schema": datasources.Schema(),
"materialize_secret": datasources.Secret(),
@@ -124,41 +127,89 @@ func Provider(version string) *schema.Provider {
}
func providerConfigure(ctx context.Context, d *schema.ResourceData, version string) (interface{}, diag.Diagnostics) {
- host := d.Get("host").(string)
- user := d.Get("user").(string)
password := d.Get("password").(string)
- port := d.Get("port").(int)
database := d.Get("database").(string)
sslmode := d.Get("sslmode").(string)
+ endpoint := d.Get("endpoint").(string)
+ cloudEndpoint := d.Get("cloud_endpoint").(string)
+ defaultRegion := clients.Region(d.Get("default_region").(string))
application_name := fmt.Sprintf("terraform-provider-materialize v%s", version)
- // Set the host in the utils package so that the region can be extracted from it
- err := utils.SetRegionFromHostname(host)
+ err := utils.SetDefaultRegion(string(defaultRegion))
if err != nil {
return nil, diag.FromErr(err)
}
- url := &url.URL{
- Scheme: "postgres",
- User: url.UserPassword(user, password),
- Host: fmt.Sprintf("%s:%d", host, port),
- Path: database,
- RawQuery: url.Values{
- "application_name": {application_name},
- "sslmode": {sslmode},
- }.Encode(),
+ // Initialize the Frontegg client.
+ fronteggClient, err := clients.NewFronteggClient(ctx, password, endpoint)
+ if err != nil {
+ return nil, diag.Errorf("Unable to create Frontegg client: %s", err)
}
- var diags diag.Diagnostics
- db, err := sqlx.Open("pgx", url.String())
+ // Initialize the Cloud API client using the Frontegg client and endpoint
+ cloudAPIClient := clients.NewCloudAPIClient(fronteggClient, cloudEndpoint)
+ regionsEnabled := make(map[clients.Region]bool)
+
+ // Get the list of cloud providers
+ providers, err := cloudAPIClient.ListCloudProviders(ctx)
if err != nil {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Error,
- Summary: "Unable to create Materialize client",
- Detail: "Unable to authenticate user for authenticated Materialize client",
- })
- return nil, diags
+ return nil, diag.Errorf("Unable to list cloud providers: %s", err)
+ }
+
+ // Store the DB clients for all regions.
+ dbClients := make(map[clients.Region]*clients.DBClient)
+
+ for _, provider := range providers {
+ regionDetails, err := cloudAPIClient.GetRegionDetails(ctx, provider)
+
+ log.Printf("[DEBUG] Region details for provider %s: %v\n", provider.ID, regionDetails)
+
+ if err != nil {
+ log.Printf("[ERROR] Error getting region details for provider %s: %v\n", provider.ID, err)
+ continue
+ }
+
+ // Check if regionDetails or RegionInfo is nil before proceeding
+ if regionDetails == nil || regionDetails.RegionInfo == nil {
+ continue
+ }
+
+ regionsEnabled[clients.Region(provider.ID)] = regionDetails.RegionInfo != nil && regionDetails.RegionInfo.Resolvable
+
+ // Get the database connection details for the region
+ host, port, err := clients.SplitHostPort(regionDetails.RegionInfo.SqlAddress)
+ if err != nil {
+ log.Printf("[ERROR] Error splitting host and port for region %s: %v\n", provider.ID, err)
+ continue
+ }
+
+ user := fronteggClient.Email
+
+ // Instantiate a new DB client for the region
+ dbClient, diags := clients.NewDBClient(host, user, password, port, database, application_name, version, sslmode)
+ if diags.HasError() {
+ log.Printf("[ERROR] Error initializing DB client for region %s: %v\n", provider.ID, diags)
+ continue
+ }
+
+ dbClients[clients.Region(provider.ID)] = dbClient
+ }
+
+ // Check if at least one region has been initialized successfully
+ if len(dbClients) == 0 {
+ return nil, diag.Errorf("No database regions were initialized. Please check your configuration.")
+ }
+
+ log.Printf("[DEBUG] Initialized DB clients for regions: %v\n", dbClients)
+
+ // Construct and return the provider meta with all clients initialized.
+ providerMeta := &utils.ProviderMeta{
+ DB: dbClients,
+ Frontegg: fronteggClient,
+ CloudAPI: cloudAPIClient,
+ DefaultRegion: clients.Region(defaultRegion),
+ RegionsEnabled: regionsEnabled,
}
- return db, diags
+ return providerMeta, nil
}
diff --git a/pkg/provider/provider_test.go b/pkg/provider/provider_test.go
index beb00ab1..0d2c6fa1 100644
--- a/pkg/provider/provider_test.go
+++ b/pkg/provider/provider_test.go
@@ -6,10 +6,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/materialize"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
- "github.com/jmoiron/sqlx"
"golang.org/x/exp/slices"
)
@@ -42,8 +42,12 @@ func testAccPreCheck(t *testing.T) {
func testAccAddColumnComment(object materialize.MaterializeObject, column, comment string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`COMMENT ON COLUMN %[1]s.%[2]s IS %[3]s;`,
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`COMMENT ON COLUMN %[1]s.%[2]s IS %[3]s;`,
object.QualifiedName(),
column,
materialize.QuoteString(comment),
@@ -54,16 +58,24 @@ func testAccAddColumnComment(object materialize.MaterializeObject, column, comme
func testAccCheckObjectDisappears(object materialize.MaterializeObject) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`DROP %[1]s %[2]s;`, object.ObjectType, object.QualifiedName()))
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`DROP %[1]s %[2]s;`, object.ObjectType, object.QualifiedName()))
return err
}
}
func testAccCheckGrantRevoked(object materialize.MaterializeObject, roleName, privilege string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(
`REVOKE %[1]s ON %[2]s %[3]s FROM "%[4]s";`,
privilege, object.ObjectType, object.QualifiedName(), roleName,
))
@@ -73,7 +85,11 @@ func testAccCheckGrantRevoked(object materialize.MaterializeObject, roleName, pr
func testAccCheckGrantExists(object materialize.MaterializeObject, grantName, roleName, privilege string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
_, ok := s.RootModule().Resources[grantName]
if !ok {
return fmt.Errorf("grant not found")
@@ -100,15 +116,23 @@ func testAccCheckGrantExists(object materialize.MaterializeObject, grantName, ro
func testAccCheckGrantDefaultPrivilegeRevoked(objectType, granteeName, targetName, privilege string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
- _, err := db.Exec(fmt.Sprintf(`ALTER DEFAULT PRIVILEGES FOR ROLE %[1]s REVOKE %[2]s ON %[3]sS FROM %[4]s;`, targetName, privilege, objectType, granteeName))
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
+ _, err = db.Exec(fmt.Sprintf(`ALTER DEFAULT PRIVILEGES FOR ROLE %[1]s REVOKE %[2]s ON %[3]sS FROM %[4]s;`, targetName, privilege, objectType, granteeName))
return err
}
}
func testAccCheckGrantDefaultPrivilegeExists(objectType, grantName, granteeName, targetName, privilege string) resource.TestCheckFunc {
return func(s *terraform.State) error {
- db := testAccProvider.Meta().(*sqlx.DB)
+ meta := testAccProvider.Meta()
+ db, _, err := utils.GetDBClientFromMeta(meta, nil)
+ if err != nil {
+ return fmt.Errorf("error getting DB client: %s", err)
+ }
_, ok := s.RootModule().Resources[grantName]
if !ok {
return fmt.Errorf("default grant not found")
diff --git a/pkg/resources/resource_app_password.go b/pkg/resources/resource_app_password.go
new file mode 100644
index 00000000..23d1e849
--- /dev/null
+++ b/pkg/resources/resource_app_password.go
@@ -0,0 +1,280 @@
+package resources
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func AppPassword() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: appPasswordCreate,
+ ReadContext: appPasswordRead,
+ DeleteContext: appPasswordDelete,
+
+ Importer: &schema.ResourceImporter{
+ StateContext: schema.ImportStatePassthroughContext,
+ },
+
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+ "owner": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "created_at": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "secret": {
+ Type: schema.TypeString,
+ Computed: true,
+ Sensitive: true,
+ },
+ "password": {
+ Type: schema.TypeString,
+ Computed: true,
+ Sensitive: true,
+ },
+ },
+ }
+}
+
+type appPasswordCreateRequest struct {
+ Description string `json:"description"`
+}
+
+type appPasswordResponse struct {
+ ClientID string `json:"clientId"`
+ Description string `json:"description"`
+ Owner string `json:"owner"`
+ CreatedAt time.Time `json:"created_at"`
+ Secret string `json:"secret"`
+}
+
+const (
+ apiTokenPath = "/identity/resources/users/api-tokens/v1"
+)
+
+func appPasswordCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ providerMeta, err := utils.GetProviderMeta(meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ // Create the app password using the helper function.
+ response, err := createAppPassword(ctx, d, providerMeta.Frontegg)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ clientId := strings.ReplaceAll(response.ClientID, "-", "")
+ secret := strings.ReplaceAll(response.Secret, "-", "")
+ appPassword := fmt.Sprintf("mzp_%s%s", clientId, secret)
+
+ // Set the Terraform resource ID and state.
+ d.SetId(response.ClientID)
+ if err := d.Set("name", response.Description); err != nil {
+ return diag.FromErr(err)
+ }
+ if err := d.Set("created_at", response.CreatedAt.Format(time.RFC3339)); err != nil {
+ return diag.FromErr(err)
+ }
+ if err := d.Set("secret", response.Secret); err != nil {
+ return diag.FromErr(err)
+ }
+ if err := d.Set("password", appPassword); err != nil {
+ return diag.FromErr(err)
+ }
+ // TODO: Get the owner from the API as it's not returned in the response.
+ // For now, we can either leave this unset or set a default value.
+ // d.Set("owner", "some-default-or-fetched-value")
+
+ return nil
+}
+
+// appPasswordRead reads the app password resource from the API.
+func appPasswordRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ providerMeta, err := utils.GetProviderMeta(meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ client := providerMeta.Frontegg
+ resourceID := d.Id()
+
+ passwords, err := listAppPasswords(ctx, client)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ foundPassword := findAppPasswordById(passwords, resourceID)
+ if foundPassword == nil {
+ d.SetId("")
+ return nil
+ }
+
+ appPassword := clients.ConstructAppPassword(foundPassword.ClientID, foundPassword.Secret)
+
+ // Update the Terraform state with the retrieved values.
+ d.Set("name", foundPassword.Description)
+ d.Set("created_at", foundPassword.CreatedAt.Format(time.RFC3339))
+ d.Set("secret", foundPassword.Secret)
+ d.Set("password", appPassword)
+ // TODO: Get the owner from the API as it's not returned in the response.
+ // d.Set("owner", foundPassword.Owner)
+
+ return nil
+}
+
+func appPasswordDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ providerMeta, err := utils.GetProviderMeta(meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ client := providerMeta.Frontegg
+ resourceID := d.Id()
+
+ err = deleteAppPassword(ctx, client, resourceID)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ d.SetId("")
+ return nil
+}
+
+// Helper function to create or make app password
+func createAppPassword(ctx context.Context, d *schema.ResourceData, client *clients.FronteggClient) (appPasswordResponse, error) {
+ var response appPasswordResponse
+
+ createRequest := appPasswordCreateRequest{
+ Description: d.Get("name").(string),
+ }
+ requestBody, err := json.Marshal(createRequest)
+ if err != nil {
+ return response, err
+ }
+
+ resp, err := doRequest(ctx, client, "POST", getApiEndpoint(client, apiTokenPath), requestBody)
+ if err != nil {
+ return response, err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusCreated {
+ return response, handleApiError(resp)
+ }
+
+ if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
+ return response, err
+ }
+
+ return response, nil
+}
+
+// Helper function to construct the full API endpoint for app passwords
+func getApiEndpoint(client *clients.FronteggClient, resourcePath string, resourceID ...string) string {
+ if len(resourceID) > 0 {
+ return fmt.Sprintf("%s%s/%s", client.Endpoint, resourcePath, resourceID[0])
+ }
+ return fmt.Sprintf("%s%s", client.Endpoint, resourcePath)
+}
+
+// Helper function to perform HTTP requests
+func doRequest(ctx context.Context, client *clients.FronteggClient, method, url string, body []byte) (*http.Response, error) {
+ req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewBuffer(body))
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Add("Content-Type", "application/json")
+
+ return client.HTTPClient.Do(req)
+}
+
+// Helper function to handle API errors
+func handleApiError(resp *http.Response) error {
+ responseBody, _ := io.ReadAll(resp.Body)
+ if resp.StatusCode == http.StatusNotFound {
+ return nil // Resource not found, equivalent to a successful delete
+ }
+ return fmt.Errorf("API error: %s - %s", resp.Status, string(responseBody))
+}
+
+// Helper function to delete an app password.
+func deleteAppPassword(ctx context.Context, client *clients.FronteggClient, resourceID string) error {
+ resp, err := doRequest(ctx, client, "DELETE", getApiEndpoint(client, apiTokenPath, resourceID), nil)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return handleApiError(resp)
+ }
+ return nil
+}
+
+// Helper function to find an app password by ID.
+func findAppPasswordById(passwords []appPasswordResponse, id string) *appPasswordResponse {
+ for _, password := range passwords {
+ if password.ClientID == id {
+ return &password
+ }
+ }
+ return nil
+}
+
+// listAppPasswords fetches a list of app passwords from the API.
+func listAppPasswords(ctx context.Context, client *clients.FronteggClient) ([]appPasswordResponse, error) {
+ var passwords []appPasswordResponse
+
+ // Construct the request URL
+ url := getApiEndpoint(client, apiTokenPath)
+
+ // Create and send the HTTP request
+ req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+ if err != nil {
+ return nil, fmt.Errorf("creating request failed: %w", err)
+ }
+ req.Header.Add("Authorization", "Bearer "+client.Token)
+
+ // Execute the request
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("executing request failed: %w", err)
+ }
+ defer resp.Body.Close()
+
+ // Check the response code
+ if resp.StatusCode != http.StatusOK {
+ return nil, handleApiError(resp)
+ }
+
+ // Decode the response body
+ responseBody, readErr := io.ReadAll(resp.Body)
+ if readErr != nil {
+ return nil, fmt.Errorf("reading response body failed: %w", readErr)
+ }
+
+ if err := json.Unmarshal(responseBody, &passwords); err != nil {
+ return nil, fmt.Errorf("decoding response failed: %w", err)
+ }
+
+ return passwords, nil
+}
diff --git a/pkg/resources/resource_app_password_test.go b/pkg/resources/resource_app_password_test.go
new file mode 100644
index 00000000..b65024fe
--- /dev/null
+++ b/pkg/resources/resource_app_password_test.go
@@ -0,0 +1,95 @@
+package resources
+
+import (
+ "context"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAppPasswordResourceCreate(t *testing.T) {
+ r := require.New(t)
+
+ in := map[string]interface{}{
+ "name": "test-app-password",
+ }
+ d := schema.TestResourceDataRaw(t, AppPassword().Schema, in)
+ r.NotNil(d)
+
+ testhelpers.WithMockFronteggServer(t, func(serverURL string) {
+ client := &clients.FronteggClient{
+ Endpoint: serverURL,
+ HTTPClient: &http.Client{},
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ }
+
+ providerMeta := &utils.ProviderMeta{
+ Frontegg: client,
+ }
+
+ if err := appPasswordCreate(context.TODO(), d, providerMeta); err != nil {
+ t.Fatal(err)
+ }
+
+ r.Equal("test-app-password", d.Get("name"))
+ r.Equal("mock-secret", d.Get("secret"))
+ })
+}
+
+func TestAppPasswordResourceRead(t *testing.T) {
+ r := require.New(t)
+
+ testhelpers.WithMockFronteggServer(t, func(serverURL string) {
+ client := &clients.FronteggClient{
+ Endpoint: serverURL,
+ HTTPClient: &http.Client{},
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ }
+
+ providerMeta := &utils.ProviderMeta{
+ Frontegg: client,
+ }
+
+ d := schema.TestResourceDataRaw(t, AppPassword().Schema, nil)
+ d.SetId("mock-client-id")
+
+ if err := appPasswordRead(context.TODO(), d, providerMeta); err != nil {
+ t.Fatal(err)
+ }
+
+ // Add assertions to check the state after read
+ r.Equal("mock-client-id", d.Id())
+ r.Equal("test-app-password", d.Get("name"))
+ })
+}
+
+func TestAppPasswordResourceDelete(t *testing.T) {
+ r := require.New(t)
+
+ testhelpers.WithMockFronteggServer(t, func(serverURL string) {
+ client := &clients.FronteggClient{
+ Endpoint: serverURL,
+ HTTPClient: &http.Client{},
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ }
+
+ providerMeta := &utils.ProviderMeta{
+ Frontegg: client,
+ }
+
+ d := schema.TestResourceDataRaw(t, AppPassword().Schema, nil)
+ d.SetId("mock-client-id")
+
+ if err := appPasswordDelete(context.TODO(), d, providerMeta); err != nil {
+ t.Fatal(err)
+ }
+
+ r.Empty(d.Id())
+ })
+}
diff --git a/pkg/resources/resource_cluster.go b/pkg/resources/resource_cluster.go
index 7166b006..4e68d44e 100644
--- a/pkg/resources/resource_cluster.go
+++ b/pkg/resources/resource_cluster.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var clusterSchema = map[string]*schema.Schema{
@@ -36,6 +35,7 @@ var clusterSchema = map[string]*schema.Schema{
"introspection_interval": IntrospectionIntervalSchema(false, []string{"size"}),
"introspection_debugging": IntrospectionDebuggingSchema(false, []string{"size"}),
"idle_arrangement_merge_effort": IdleArrangementMergeEffortSchema(false, []string{"size"}),
+ "region": RegionSchema(),
}
func Cluster() *schema.Resource {
@@ -57,7 +57,12 @@ func Cluster() *schema.Resource {
func clusterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanCluster(meta.(*sqlx.DB), utils.ExtractId(i))
+
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanCluster(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -65,7 +70,7 @@ func clusterRead(ctx context.Context, d *schema.ResourceData, meta interface{})
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.ClusterName.String); err != nil {
return diag.FromErr(err)
@@ -97,8 +102,12 @@ func clusterRead(ctx context.Context, d *schema.ResourceData, meta interface{})
func clusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
clusterName := d.Get("name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CLUSTER", Name: clusterName}
- b := materialize.NewClusterBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewClusterBuilder(metaDb, o)
// managed cluster options
if size, ok := d.GetOk("size"); ok {
@@ -139,7 +148,7 @@ func clusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -150,7 +159,7 @@ func clusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -160,11 +169,11 @@ func clusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}
}
// set id
- i, err := materialize.ClusterId(meta.(*sqlx.DB), o)
+ i, err := materialize.ClusterId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return clusterRead(ctx, d, meta)
}
@@ -172,17 +181,21 @@ func clusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}
func clusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
clusterName := d.Get("name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CLUSTER", Name: clusterName}
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
}
}
- b := materialize.NewClusterBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewClusterBuilder(metaDb, o)
if _, ok := d.GetOk("size"); ok {
if d.HasChange("size") {
_, newSize := d.GetChange("size")
@@ -209,7 +222,7 @@ func clusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}
// if d.HasChange("availability_zones") {
// _, n := d.GetChange("availability_zones")
// azs := materialize.GetSliceValueString(n.([]interface{}))
- // b := materialize.NewClusterBuilder(meta.(*sqlx.DB), o)
+ // b := materialize.NewClusterBuilder(metaDb, o)
// if err := b.SetAvailabilityZones(azs); err != nil {
// return diag.FromErr(err)
// }
@@ -239,7 +252,7 @@ func clusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -252,8 +265,12 @@ func clusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}
func clusterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
clusterName := d.Get("name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: clusterName}
- b := materialize.NewClusterBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewClusterBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_cluster_replica.go b/pkg/resources/resource_cluster_replica.go
index 227e3026..05baa746 100644
--- a/pkg/resources/resource_cluster_replica.go
+++ b/pkg/resources/resource_cluster_replica.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var clusterReplicaSchema = map[string]*schema.Schema{
@@ -29,6 +28,7 @@ var clusterReplicaSchema = map[string]*schema.Schema{
"introspection_interval": IntrospectionIntervalSchema(true, []string{}),
"introspection_debugging": IntrospectionDebuggingSchema(true, []string{}),
"idle_arrangement_merge_effort": IdleArrangementMergeEffortSchema(true, []string{}),
+ "region": RegionSchema(),
}
func ClusterReplica() *schema.Resource {
@@ -53,7 +53,11 @@ func ClusterReplica() *schema.Resource {
func clusterReplicaRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanClusterReplica(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanClusterReplica(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -61,7 +65,7 @@ func clusterReplicaRead(ctx context.Context, d *schema.ResourceData, meta interf
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.ReplicaName.String); err != nil {
return diag.FromErr(err)
@@ -94,12 +98,17 @@ func clusterReplicaCreate(ctx context.Context, d *schema.ResourceData, meta inte
replicaName := d.Get("name").(string)
clusterName := d.Get("cluster_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{
ObjectType: "CLUSTER REPLICA",
Name: replicaName,
ClusterName: clusterName,
}
- b := materialize.NewClusterReplicaBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewClusterReplicaBuilder(metaDb, o)
if v, ok := d.GetOk("size"); ok {
b.Size(v.(string))
@@ -132,7 +141,7 @@ func clusterReplicaCreate(ctx context.Context, d *schema.ResourceData, meta inte
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -142,11 +151,11 @@ func clusterReplicaCreate(ctx context.Context, d *schema.ResourceData, meta inte
}
// set id
- i, err := materialize.ClusterReplicaId(meta.(*sqlx.DB), o)
+ i, err := materialize.ClusterReplicaId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return clusterReplicaRead(ctx, d, meta)
}
@@ -155,6 +164,10 @@ func clusterReplicaUpdate(ctx context.Context, d *schema.ResourceData, meta inte
replicaName := d.Get("name").(string)
clusterName := d.Get("cluster_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{
ObjectType: "CLUSTER REPLICA",
Name: replicaName,
@@ -163,7 +176,7 @@ func clusterReplicaUpdate(ctx context.Context, d *schema.ResourceData, meta inte
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -177,8 +190,12 @@ func clusterReplicaDelete(ctx context.Context, d *schema.ResourceData, meta inte
replicaName := d.Get("name").(string)
clusterName := d.Get("cluster_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: replicaName, ClusterName: clusterName}
- b := materialize.NewClusterReplicaBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewClusterReplicaBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_cluster_replica_test.go b/pkg/resources/resource_cluster_replica_test.go
index ba42d50e..bf7bba8a 100644
--- a/pkg/resources/resource_cluster_replica_test.go
+++ b/pkg/resources/resource_cluster_replica_test.go
@@ -9,7 +9,6 @@ import (
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -29,7 +28,7 @@ func TestResourceClusterReplicaCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, ClusterReplica().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(`
CREATE CLUSTER REPLICA "cluster"."replica"
@@ -59,7 +58,7 @@ func TestResourceClusterReplicaCreate(t *testing.T) {
// Confirm id is updated with region for 0.4.0
func TestResourceClusterReplicaReadIdMigration(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -71,7 +70,7 @@ func TestResourceClusterReplicaReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_cluster_replicas.id = 'u1'`
testhelpers.MockClusterReplicaScan(mock, pp)
@@ -96,7 +95,7 @@ func TestResourceClusterReplicaDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, ClusterReplica().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP CLUSTER REPLICA "cluster"."replica";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := clusterReplicaDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_cluster_test.go b/pkg/resources/resource_cluster_test.go
index 6c9e469b..c9519321 100644
--- a/pkg/resources/resource_cluster_test.go
+++ b/pkg/resources/resource_cluster_test.go
@@ -9,7 +9,6 @@ import (
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -30,7 +29,7 @@ func TestResourceClusterCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Cluster().Schema, inCluster)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(`
CREATE CLUSTER "cluster"
@@ -60,7 +59,7 @@ func TestResourceClusterCreate(t *testing.T) {
// Confirm id is updated with region for 0.4.0
func TestResourceClusterReadIdMigration(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -72,7 +71,7 @@ func TestResourceClusterReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_clusters.id = 'u1'`
testhelpers.MockClusterScan(mock, pp)
@@ -98,7 +97,7 @@ func TestResourceClusterZeroReplicationCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Cluster().Schema, inClusterZeroReplication)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(`
CREATE CLUSTER "cluster"
@@ -127,7 +126,7 @@ func TestResourceClusterDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Cluster().Schema, inCluster)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP CLUSTER "cluster";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := clusterDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_connection.go b/pkg/resources/resource_connection.go
index 99e631ed..2deacd68 100644
--- a/pkg/resources/resource_connection.go
+++ b/pkg/resources/resource_connection.go
@@ -9,13 +9,16 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func connectionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanConnection(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanConnection(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -23,7 +26,7 @@ func connectionRead(ctx context.Context, d *schema.ResourceData, meta interface{
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.ConnectionName.String); err != nil {
return diag.FromErr(err)
@@ -58,12 +61,16 @@ func connectionUpdate(ctx context.Context, d *schema.ResourceData, meta interfac
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnection(meta.(*sqlx.DB), o)
+ b := materialize.NewConnection(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -71,7 +78,7 @@ func connectionUpdate(ctx context.Context, d *schema.ResourceData, meta interfac
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -80,7 +87,7 @@ func connectionUpdate(ctx context.Context, d *schema.ResourceData, meta interfac
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -95,8 +102,12 @@ func connectionDelete(ctx context.Context, d *schema.ResourceData, meta interfac
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnection(meta.(*sqlx.DB), o)
+ b := materialize.NewConnection(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_connection_aws_privatelink.go b/pkg/resources/resource_connection_aws_privatelink.go
index 48ce18d8..6b5e5d3c 100644
--- a/pkg/resources/resource_connection_aws_privatelink.go
+++ b/pkg/resources/resource_connection_aws_privatelink.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var connectionAwsPrivatelinkSchema = map[string]*schema.Schema{
@@ -39,6 +38,7 @@ var connectionAwsPrivatelinkSchema = map[string]*schema.Schema{
Sensitive: true,
},
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func ConnectionAwsPrivatelink() *schema.Resource {
@@ -68,7 +68,11 @@ type ConnectionAwsPrivatelinkParams struct {
func connectionAwsPrivatelinkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanConnectionAwsPrivatelink(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanConnectionAwsPrivatelink(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -76,7 +80,7 @@ func connectionAwsPrivatelinkRead(ctx context.Context, d *schema.ResourceData, m
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.ConnectionName.String); err != nil {
return diag.FromErr(err)
@@ -115,8 +119,12 @@ func connectionAwsPrivatelinkCreate(ctx context.Context, d *schema.ResourceData,
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnectionAwsPrivatelinkBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewConnectionAwsPrivatelinkBuilder(metaDb, o)
if v, ok := d.GetOk("service_name"); ok {
b.PrivateLinkServiceName(v.(string))
@@ -134,7 +142,7 @@ func connectionAwsPrivatelinkCreate(ctx context.Context, d *schema.ResourceData,
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -145,7 +153,7 @@ func connectionAwsPrivatelinkCreate(ctx context.Context, d *schema.ResourceData,
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -155,11 +163,11 @@ func connectionAwsPrivatelinkCreate(ctx context.Context, d *schema.ResourceData,
}
// set id
- i, err := materialize.ConnectionId(meta.(*sqlx.DB), o)
+ i, err := materialize.ConnectionId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return connectionAwsPrivatelinkRead(ctx, d, meta)
}
@@ -169,12 +177,16 @@ func connectionAwsPrivatelinkUpdate(ctx context.Context, d *schema.ResourceData,
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnectionAwsPrivatelinkBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewConnectionAwsPrivatelinkBuilder(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -182,7 +194,7 @@ func connectionAwsPrivatelinkUpdate(ctx context.Context, d *schema.ResourceData,
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
}
@@ -190,7 +202,7 @@ func connectionAwsPrivatelinkUpdate(ctx context.Context, d *schema.ResourceData,
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_connection_aws_privatelink_test.go b/pkg/resources/resource_connection_aws_privatelink_test.go
index 723b575c..160fd645 100644
--- a/pkg/resources/resource_connection_aws_privatelink_test.go
+++ b/pkg/resources/resource_connection_aws_privatelink_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -25,7 +25,7 @@ func TestResourceConnectionAwsPrivatelinkCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, ConnectionAwsPrivatelink().Schema, inAwsPrivatelink)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE CONNECTION "database"."schema"."conn"
@@ -56,7 +56,7 @@ func TestResourceConnectionAwsPrivatelinkReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_connections.id = 'u1'`
testhelpers.MockConnectionAwsPrivatelinkScan(mock, pp)
@@ -81,7 +81,7 @@ func TestResourceConnectionAwsPrivatelinkUpdate(t *testing.T) {
d.Set("name", "old_conn")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER CONNECTION "database"."schema"."" RENAME TO "conn";`).WillReturnResult(sqlmock.NewResult(1, 1))
// Query Params
diff --git a/pkg/resources/resource_connection_confluent_schema_registry.go b/pkg/resources/resource_connection_confluent_schema_registry.go
index 9c9039f0..706a8a88 100644
--- a/pkg/resources/resource_connection_confluent_schema_registry.go
+++ b/pkg/resources/resource_connection_confluent_schema_registry.go
@@ -9,7 +9,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var connectionConfluentSchemaRegistrySchema = map[string]*schema.Schema{
@@ -32,6 +31,7 @@ var connectionConfluentSchemaRegistrySchema = map[string]*schema.Schema{
"aws_privatelink": IdentifierSchema("aws_privatelink", "The AWS PrivateLink configuration for the Confluent Schema Registry.", false),
"validate": ValidateConnectionSchema(),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func ConnectionConfluentSchemaRegistry() *schema.Resource {
@@ -56,8 +56,12 @@ func connectionConfluentSchemaRegistryCreate(ctx context.Context, d *schema.Reso
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnectionConfluentSchemaRegistryBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewConnectionConfluentSchemaRegistryBuilder(metaDb, o)
if v, ok := d.GetOk("url"); ok {
b.ConfluentSchemaRegistryUrl(v.(string))
@@ -109,7 +113,7 @@ func connectionConfluentSchemaRegistryCreate(ctx context.Context, d *schema.Reso
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -120,7 +124,7 @@ func connectionConfluentSchemaRegistryCreate(ctx context.Context, d *schema.Reso
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -130,11 +134,11 @@ func connectionConfluentSchemaRegistryCreate(ctx context.Context, d *schema.Reso
}
// set id
- i, err := materialize.ConnectionId(meta.(*sqlx.DB), o)
+ i, err := materialize.ConnectionId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return connectionRead(ctx, d, meta)
}
diff --git a/pkg/resources/resource_connection_confluent_schema_registry_test.go b/pkg/resources/resource_connection_confluent_schema_registry_test.go
index 0aa85c52..b5b12077 100644
--- a/pkg/resources/resource_connection_confluent_schema_registry_test.go
+++ b/pkg/resources/resource_connection_confluent_schema_registry_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -43,7 +43,7 @@ func TestResourceConnectionConfluentSchemaRegistryCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, ConnectionConfluentSchemaRegistry().Schema, inConfluentSchemaRegistry)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE CONNECTION "database"."schema"."conn" TO CONFLUENT SCHEMA REGISTRY \(URL 'http://localhost:8081', USERNAME = 'user', PASSWORD = SECRET "materialize"."public"."password", SSL CERTIFICATE AUTHORITY = SECRET "materialize"."public"."ssl", SSL CERTIFICATE = SECRET "materialize"."public"."ssl", SSL KEY = SECRET "ssl_key"."public"."ssl", AWS PRIVATELINK "materialize"."public"."privatelink", SSH TUNNEL "materialize"."tunnel_schema"."tunnel"\)`,
diff --git a/pkg/resources/resource_connection_kafka.go b/pkg/resources/resource_connection_kafka.go
index ea33e9da..e6f9aada 100644
--- a/pkg/resources/resource_connection_kafka.go
+++ b/pkg/resources/resource_connection_kafka.go
@@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
- "github.com/jmoiron/sqlx"
)
var connectionKafkaSchema = map[string]*schema.Schema{
@@ -83,6 +82,7 @@ var connectionKafkaSchema = map[string]*schema.Schema{
"ssh_tunnel": IdentifierSchema("ssh_tunnel", "The default SSH tunnel configuration for the Kafka brokers.", false),
"validate": ValidateConnectionSchema(),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func ConnectionKafka() *schema.Resource {
@@ -107,8 +107,12 @@ func connectionKafkaCreate(ctx context.Context, d *schema.ResourceData, meta int
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnectionKafkaBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewConnectionKafkaBuilder(metaDb, o)
if v, ok := d.GetOk("kafka_broker"); ok {
brokers := materialize.GetKafkaBrokersStruct(v)
@@ -168,7 +172,7 @@ func connectionKafkaCreate(ctx context.Context, d *schema.ResourceData, meta int
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -179,7 +183,7 @@ func connectionKafkaCreate(ctx context.Context, d *schema.ResourceData, meta int
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -189,11 +193,11 @@ func connectionKafkaCreate(ctx context.Context, d *schema.ResourceData, meta int
}
// set id
- i, err := materialize.ConnectionId(meta.(*sqlx.DB), o)
+ i, err := materialize.ConnectionId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return connectionRead(ctx, d, meta)
}
diff --git a/pkg/resources/resource_connection_kafka_test.go b/pkg/resources/resource_connection_kafka_test.go
index 151871d0..0402393b 100644
--- a/pkg/resources/resource_connection_kafka_test.go
+++ b/pkg/resources/resource_connection_kafka_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -42,7 +42,7 @@ func TestResourceConnectionKafkaCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, ConnectionKafka().Schema, inKafka)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE CONNECTION "database"."schema"."conn"
diff --git a/pkg/resources/resource_connection_postgres.go b/pkg/resources/resource_connection_postgres.go
index 44acbd79..acbaa6da 100644
--- a/pkg/resources/resource_connection_postgres.go
+++ b/pkg/resources/resource_connection_postgres.go
@@ -9,7 +9,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var connectionPostgresSchema = map[string]*schema.Schema{
@@ -52,6 +51,7 @@ var connectionPostgresSchema = map[string]*schema.Schema{
"aws_privatelink": IdentifierSchema("aws_privatelink", "The AWS PrivateLink configuration for the Postgres database.", false),
"validate": ValidateConnectionSchema(),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func ConnectionPostgres() *schema.Resource {
@@ -76,8 +76,12 @@ func connectionPostgresCreate(ctx context.Context, d *schema.ResourceData, meta
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnectionPostgresBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewConnectionPostgresBuilder(metaDb, o)
if v, ok := d.GetOk("connection_type"); ok {
b.ConnectionType(v.(string))
@@ -145,7 +149,7 @@ func connectionPostgresCreate(ctx context.Context, d *schema.ResourceData, meta
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -156,7 +160,7 @@ func connectionPostgresCreate(ctx context.Context, d *schema.ResourceData, meta
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -166,11 +170,11 @@ func connectionPostgresCreate(ctx context.Context, d *schema.ResourceData, meta
}
// set id
- i, err := materialize.ConnectionId(meta.(*sqlx.DB), o)
+ i, err := materialize.ConnectionId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return connectionRead(ctx, d, meta)
}
diff --git a/pkg/resources/resource_connection_postgres_test.go b/pkg/resources/resource_connection_postgres_test.go
index e90bac1c..3036b18e 100644
--- a/pkg/resources/resource_connection_postgres_test.go
+++ b/pkg/resources/resource_connection_postgres_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -48,7 +48,7 @@ func TestResourceConnectionPostgresCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, ConnectionPostgres().Schema, inPostgres)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE CONNECTION "database"."schema"."conn" TO POSTGRES \(HOST 'postgres_host', PORT 5432, USER SECRET "materialize"."public"."user", PASSWORD SECRET "materialize"."public"."password", SSL MODE 'verify-full', SSH TUNNEL "tunnel_database"."tunnel_schema"."ssh_conn", SSL CERTIFICATE AUTHORITY SECRET "ssl_database"."public"."root", SSL CERTIFICATE SECRET "materialize"."public"."cert", SSL KEY SECRET "materialize"."public"."key", AWS PRIVATELINK "materialize"."public"."link", DATABASE 'default'\);`,
diff --git a/pkg/resources/resource_connection_ssh_tunnel.go b/pkg/resources/resource_connection_ssh_tunnel.go
index 93ec6e54..f8b9578e 100644
--- a/pkg/resources/resource_connection_ssh_tunnel.go
+++ b/pkg/resources/resource_connection_ssh_tunnel.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var connectionSshTunnelSchema = map[string]*schema.Schema{
@@ -48,6 +47,7 @@ var connectionSshTunnelSchema = map[string]*schema.Schema{
Computed: true,
},
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func ConnectionSshTunnel() *schema.Resource {
@@ -70,7 +70,11 @@ func ConnectionSshTunnel() *schema.Resource {
func connectionSshTunnelRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanConnectionSshTunnel(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanConnectionSshTunnel(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -78,7 +82,7 @@ func connectionSshTunnelRead(ctx context.Context, d *schema.ResourceData, meta i
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.ConnectionName.String); err != nil {
return diag.FromErr(err)
@@ -121,8 +125,12 @@ func connectionSshTunnelCreate(ctx context.Context, d *schema.ResourceData, meta
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnectionSshTunnelBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewConnectionSshTunnelBuilder(metaDb, o)
b.SSHHost(d.Get("host").(string))
b.SSHUser(d.Get("user").(string))
@@ -135,7 +143,7 @@ func connectionSshTunnelCreate(ctx context.Context, d *schema.ResourceData, meta
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -146,7 +154,7 @@ func connectionSshTunnelCreate(ctx context.Context, d *schema.ResourceData, meta
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -156,11 +164,11 @@ func connectionSshTunnelCreate(ctx context.Context, d *schema.ResourceData, meta
}
// set id
- i, err := materialize.ConnectionId(meta.(*sqlx.DB), o)
+ i, err := materialize.ConnectionId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return connectionSshTunnelRead(ctx, d, meta)
}
@@ -170,12 +178,16 @@ func connectionSshTunnelUpdate(ctx context.Context, d *schema.ResourceData, meta
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: connectionName, SchemaName: schemaName, DatabaseName: databaseName}
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "CONNECTION", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewConnectionSshTunnelBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewConnectionSshTunnelBuilder(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -183,7 +195,7 @@ func connectionSshTunnelUpdate(ctx context.Context, d *schema.ResourceData, meta
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
}
@@ -191,7 +203,7 @@ func connectionSshTunnelUpdate(ctx context.Context, d *schema.ResourceData, meta
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_connection_ssh_tunnel_test.go b/pkg/resources/resource_connection_ssh_tunnel_test.go
index 06b00e2b..233eff79 100644
--- a/pkg/resources/resource_connection_ssh_tunnel_test.go
+++ b/pkg/resources/resource_connection_ssh_tunnel_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -29,7 +29,7 @@ func TestResourceConnectionSshTunnelCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, ConnectionSshTunnel().Schema, inSshTunnel)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE CONNECTION "database"."schema"."conn" TO SSH TUNNEL \(HOST 'localhost', USER 'user', PORT 123\);`,
@@ -62,7 +62,7 @@ func TestResourceConnectionSshTunnelReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_connections.id = 'u1'`
testhelpers.MockConnectionSshTunnelScan(mock, pp)
@@ -86,7 +86,7 @@ func TestResourceConnectionSshTunnelUpdate(t *testing.T) {
d.Set("name", "old_conn")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER CONNECTION "database"."schema"."" RENAME TO "conn";`).WillReturnResult(sqlmock.NewResult(1, 1))
// Comment
diff --git a/pkg/resources/resource_connection_test.go b/pkg/resources/resource_connection_test.go
index 33f744ba..7d7eef71 100644
--- a/pkg/resources/resource_connection_test.go
+++ b/pkg/resources/resource_connection_test.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -29,7 +28,7 @@ func TestResourceConnectionUpdate(t *testing.T) {
d.Set("name", "old_conn")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER CONNECTION "database"."schema"."" RENAME TO "conn";`).WillReturnResult(sqlmock.NewResult(1, 1))
// Query Params
@@ -46,7 +45,7 @@ func TestResourceConnectionUpdate(t *testing.T) {
// All connections (other than AWS Privatelink and SSH Tunnel)
// share the same read function
func TestResourceConnectionReadIdMigration(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
d := schema.TestResourceDataRaw(t, ConnectionKafka().Schema, inConnection)
r.NotNil(d)
@@ -54,7 +53,7 @@ func TestResourceConnectionReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
p := `WHERE mz_connections.id = 'u1'`
testhelpers.MockConnectionScan(mock, p)
@@ -76,7 +75,7 @@ func TestResourceConnectionDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, ConnectionKafka().Schema, inConnection)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP CONNECTION "database"."schema"."conn";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := connectionDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_database.go b/pkg/resources/resource_database.go
index 872d60c0..31870d07 100644
--- a/pkg/resources/resource_database.go
+++ b/pkg/resources/resource_database.go
@@ -10,13 +10,13 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var databaseSchema = map[string]*schema.Schema{
"name": ObjectNameSchema("database", true, true),
"comment": CommentSchema(false),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func Database() *schema.Resource {
@@ -39,7 +39,12 @@ func Database() *schema.Resource {
func databaseRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanDatabase(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ s, err := materialize.ScanDatabase(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -47,7 +52,7 @@ func databaseRead(ctx context.Context, d *schema.ResourceData, meta interface{})
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.DatabaseName.String); err != nil {
return diag.FromErr(err)
@@ -67,8 +72,13 @@ func databaseRead(ctx context.Context, d *schema.ResourceData, meta interface{})
func databaseCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
databaseName := d.Get("name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{ObjectType: "DATABASE", Name: databaseName}
- b := materialize.NewDatabaseBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewDatabaseBuilder(metaDb, o)
// create resource
if err := b.Create(); err != nil {
@@ -77,7 +87,7 @@ func databaseCreate(ctx context.Context, d *schema.ResourceData, meta interface{
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -88,7 +98,7 @@ func databaseCreate(ctx context.Context, d *schema.ResourceData, meta interface{
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -98,11 +108,11 @@ func databaseCreate(ctx context.Context, d *schema.ResourceData, meta interface{
}
// set id
- i, err := materialize.DatabaseId(meta.(*sqlx.DB), o)
+ i, err := materialize.DatabaseId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return databaseRead(ctx, d, meta)
}
@@ -110,8 +120,13 @@ func databaseCreate(ctx context.Context, d *schema.ResourceData, meta interface{
func databaseUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
databaseName := d.Get("name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{ObjectType: "DATABASE", Name: databaseName}
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
@@ -122,7 +137,7 @@ func databaseUpdate(ctx context.Context, d *schema.ResourceData, meta interface{
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -135,8 +150,13 @@ func databaseUpdate(ctx context.Context, d *schema.ResourceData, meta interface{
func databaseDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
databaseName := d.Get("name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{Name: databaseName}
- b := materialize.NewDatabaseBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewDatabaseBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_database_test.go b/pkg/resources/resource_database_test.go
index 785c277b..15a49cc2 100644
--- a/pkg/resources/resource_database_test.go
+++ b/pkg/resources/resource_database_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -21,7 +21,7 @@ func TestResourceDatabaseCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Database().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE DATABASE "database";`,
@@ -53,7 +53,7 @@ func TestResourceDatabaseReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_databases.id = 'u1'`
testhelpers.MockDatabaseScan(mock, pp)
@@ -77,7 +77,7 @@ func TestResourceDatabaseDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Database().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP DATABASE "database";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := databaseDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant.go b/pkg/resources/resource_grant.go
index 8c35df1f..2760df5d 100644
--- a/pkg/resources/resource_grant.go
+++ b/pkg/resources/resource_grant.go
@@ -11,7 +11,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"golang.org/x/exp/slices"
)
@@ -38,6 +37,11 @@ func parsePrivilegeKey(id string) (GrantPrivilegeKey, error) {
func grantRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
key, err := parsePrivilegeKey(i)
if err != nil {
log.Printf("[WARN] malformed privilege (%s), removing from state file", d.Id())
@@ -45,7 +49,7 @@ func grantRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
return nil
}
- p, err := materialize.ScanPrivileges(meta.(*sqlx.DB), key.objectType, key.objectId)
+ p, err := materialize.ScanPrivileges(metaDb, key.objectType, key.objectId)
if err == sql.ErrNoRows {
log.Printf("[WARN] grant (%s) not found, removing from state file", d.Id())
d.SetId("")
@@ -55,6 +59,9 @@ func grantRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
}
privilegeMap, err := materialize.MapGrantPrivileges(p)
+ if err != nil {
+ return diag.FromErr(err)
+ }
privilege := d.Get("privilege").(string)
if !slices.Contains(privilegeMap[key.roleId], privilege) {
log.Printf("[DEBUG] %s object does not contain privilege %s", i, privilege)
@@ -62,6 +69,6 @@ func grantRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
d.SetId("")
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return nil
}
diff --git a/pkg/resources/resource_grant_cluster.go b/pkg/resources/resource_grant_cluster.go
index c747cd86..f1587d8e 100644
--- a/pkg/resources/resource_grant_cluster.go
+++ b/pkg/resources/resource_grant_cluster.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantClusterSchema = map[string]*schema.Schema{
@@ -20,6 +19,7 @@ var grantClusterSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantCluster() *schema.Resource {
@@ -48,7 +48,12 @@ func grantClusterCreate(ctx context.Context, d *schema.ResourceData, meta interf
Name: clusterName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -56,17 +61,17 @@ func grantClusterCreate(ctx context.Context, d *schema.ResourceData, meta interf
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -77,8 +82,13 @@ func grantClusterDelete(ctx context.Context, d *schema.ResourceData, meta interf
privilege := d.Get("privilege").(string)
clusterName := d.Get("cluster_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_cluster_default_privilege.go b/pkg/resources/resource_grant_cluster_default_privilege.go
index 3c8ef4c2..0bf97104 100644
--- a/pkg/resources/resource_grant_cluster_default_privilege.go
+++ b/pkg/resources/resource_grant_cluster_default_privilege.go
@@ -8,13 +8,13 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantClusterDefaultPrivilegeSchema = map[string]*schema.Schema{
"grantee_name": GranteeNameSchema(),
"target_role_name": TargetRoleNameSchema(),
"privilege": PrivilegeSchema("CLUSTER"),
+ "region": RegionSchema(),
}
func GrantClusterDefaultPrivilege() *schema.Resource {
@@ -38,7 +38,12 @@ func grantClusterDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceD
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "CLUSTER", granteeName, targetName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "CLUSTER", granteeName, targetName, privilege)
// create resource
if err := b.Grant(); err != nil {
@@ -46,17 +51,17 @@ func grantClusterDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceD
}
// Query ids
- gId, err := materialize.RoleId(meta.(*sqlx.DB), granteeName)
+ gId, err := materialize.RoleId(metaDb, granteeName)
if err != nil {
return diag.FromErr(err)
}
- tId, err := materialize.RoleId(meta.(*sqlx.DB), targetName)
+ tId, err := materialize.RoleId(metaDb, targetName)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, "CLUSTER", gId, tId, "", "", privilege)
+ key := b.GrantKey(string(region), "CLUSTER", gId, tId, "", "", privilege)
d.SetId(key)
return grantDefaultPrivilegeRead(ctx, d, meta)
@@ -67,7 +72,12 @@ func grantClusterDefaultPrivilegeDelete(ctx context.Context, d *schema.ResourceD
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "CLUSTER", granteenName, targetName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "CLUSTER", granteenName, targetName, privilege)
if err := b.Revoke(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_grant_cluster_default_privilege_test.go b/pkg/resources/resource_grant_cluster_default_privilege_test.go
index 42239e50..79623d5d 100644
--- a/pkg/resources/resource_grant_cluster_default_privilege_test.go
+++ b/pkg/resources/resource_grant_cluster_default_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantClusterDefaultPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantClusterDefaultPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantClusterDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" GRANT USAGE ON CLUSTERS TO "project_managers";`,
@@ -66,7 +65,7 @@ func TestResourceGrantClusterDefaultPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantClusterDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" REVOKE USAGE ON CLUSTERS FROM "project_managers";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantClusterDefaultPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_cluster_test.go b/pkg/resources/resource_grant_cluster_test.go
index 98bf8540..1cce534c 100644
--- a/pkg/resources/resource_grant_cluster_test.go
+++ b/pkg/resources/resource_grant_cluster_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantClusterCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantClusterCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantCluster().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT CREATE ON CLUSTER "materialize" TO "joe";`,
@@ -63,7 +62,7 @@ func TestResourceGrantClusterDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantCluster().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE CREATE ON CLUSTER "materialize" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantClusterDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_connection.go b/pkg/resources/resource_grant_connection.go
index 33c8ec1c..d90ee449 100644
--- a/pkg/resources/resource_grant_connection.go
+++ b/pkg/resources/resource_grant_connection.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantConnectionSchema = map[string]*schema.Schema{
@@ -32,6 +31,7 @@ var grantConnectionSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantConnection() *schema.Resource {
@@ -64,7 +64,12 @@ func grantConnectionCreate(ctx context.Context, d *schema.ResourceData, meta int
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -72,17 +77,17 @@ func grantConnectionCreate(ctx context.Context, d *schema.ResourceData, meta int
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -95,8 +100,13 @@ func grantConnectionDelete(ctx context.Context, d *schema.ResourceData, meta int
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_connection_default_privilege.go b/pkg/resources/resource_grant_connection_default_privilege.go
index 751bbb3a..f29fc880 100644
--- a/pkg/resources/resource_grant_connection_default_privilege.go
+++ b/pkg/resources/resource_grant_connection_default_privilege.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantConnectionDefaultPrivilegeSchema = map[string]*schema.Schema{
@@ -17,6 +16,7 @@ var grantConnectionDefaultPrivilegeSchema = map[string]*schema.Schema{
"database_name": GrantDefaultDatabaseNameSchema(),
"schema_name": GrantDefaultSchemaNameSchema(),
"privilege": PrivilegeSchema("CONNECTION"),
+ "region": RegionSchema(),
}
func GrantConnectionDefaultPrivilege() *schema.Resource {
@@ -40,7 +40,12 @@ func grantConnectionDefaultPrivilegeCreate(ctx context.Context, d *schema.Resour
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "CONNECTION", granteeName, targetName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "CONNECTION", granteeName, targetName, privilege)
var database, schema string
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
@@ -59,32 +64,32 @@ func grantConnectionDefaultPrivilegeCreate(ctx context.Context, d *schema.Resour
}
// Query ids
- gId, err := materialize.RoleId(meta.(*sqlx.DB), granteeName)
+ gId, err := materialize.RoleId(metaDb, granteeName)
if err != nil {
return diag.FromErr(err)
}
- tId, err := materialize.RoleId(meta.(*sqlx.DB), targetName)
+ tId, err := materialize.RoleId(metaDb, targetName)
if err != nil {
return diag.FromErr(err)
}
var dId, sId string
if database != "" {
- dId, err = materialize.DatabaseId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: database})
+ dId, err = materialize.DatabaseId(metaDb, materialize.MaterializeObject{Name: database})
if err != nil {
return diag.FromErr(err)
}
}
if schema != "" {
- sId, err = materialize.SchemaId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: schema, DatabaseName: database})
+ sId, err = materialize.SchemaId(metaDb, materialize.MaterializeObject{Name: schema, DatabaseName: database})
if err != nil {
return diag.FromErr(err)
}
}
- key := b.GrantKey(utils.Region, "CONNECTION", gId, tId, dId, sId, privilege)
+ key := b.GrantKey(string(region), "CONNECTION", gId, tId, dId, sId, privilege)
d.SetId(key)
return grantDefaultPrivilegeRead(ctx, d, meta)
@@ -95,7 +100,12 @@ func grantConnectionDefaultPrivilegeDelete(ctx context.Context, d *schema.Resour
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "CONNECTION", granteenName, targetName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "CONNECTION", granteenName, targetName, privilege)
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
b.DatabaseName(v.(string))
diff --git a/pkg/resources/resource_grant_connection_default_privilege_test.go b/pkg/resources/resource_grant_connection_default_privilege_test.go
index 63bd3086..feb27d6d 100644
--- a/pkg/resources/resource_grant_connection_default_privilege_test.go
+++ b/pkg/resources/resource_grant_connection_default_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantConnectionDefaultPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantConnectionDefaultPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantConnectionDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" GRANT USAGE ON CONNECTIONS TO "project_managers";`,
@@ -66,7 +65,7 @@ func TestResourceGrantConnectionDefaultPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantConnectionDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" REVOKE USAGE ON CONNECTIONS FROM "project_managers";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantConnectionDefaultPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_connection_test.go b/pkg/resources/resource_grant_connection_test.go
index 2399cc37..5cb4b219 100644
--- a/pkg/resources/resource_grant_connection_test.go
+++ b/pkg/resources/resource_grant_connection_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantConnectionCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -26,7 +25,7 @@ func TestResourceGrantConnectionCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantConnection().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT USAGE ON CONNECTION "database"."schema"."conn" TO "joe";`,
@@ -67,7 +66,7 @@ func TestResourceGrantConnectionDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantConnection().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE USAGE ON CONNECTION "database"."schema"."conn" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantConnectionDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_database.go b/pkg/resources/resource_grant_database.go
index 2912d0c4..64b8b580 100644
--- a/pkg/resources/resource_grant_database.go
+++ b/pkg/resources/resource_grant_database.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantDatabaseSchema = map[string]*schema.Schema{
@@ -20,6 +19,7 @@ var grantDatabaseSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantDatabase() *schema.Resource {
@@ -48,7 +48,12 @@ func grantDatabaseCreate(ctx context.Context, d *schema.ResourceData, meta inter
Name: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -56,17 +61,17 @@ func grantDatabaseCreate(ctx context.Context, d *schema.ResourceData, meta inter
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -77,8 +82,13 @@ func grantDatabaseDelete(ctx context.Context, d *schema.ResourceData, meta inter
privilege := d.Get("privilege").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_database_default_privilege.go b/pkg/resources/resource_grant_database_default_privilege.go
index 093b4a6d..c92a51aa 100644
--- a/pkg/resources/resource_grant_database_default_privilege.go
+++ b/pkg/resources/resource_grant_database_default_privilege.go
@@ -8,13 +8,13 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantDatabaseDefaultPrivilegeSchema = map[string]*schema.Schema{
"grantee_name": GranteeNameSchema(),
"target_role_name": TargetRoleNameSchema(),
"privilege": PrivilegeSchema("DATABASE"),
+ "region": RegionSchema(),
}
func GrantDatabaseDefaultPrivilege() *schema.Resource {
@@ -38,7 +38,12 @@ func grantDatabaseDefaultPrivilegeCreate(ctx context.Context, d *schema.Resource
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "DATABASE", granteeName, targetName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "DATABASE", granteeName, targetName, privilege)
// create resource
if err := b.Grant(); err != nil {
@@ -46,17 +51,17 @@ func grantDatabaseDefaultPrivilegeCreate(ctx context.Context, d *schema.Resource
}
// Query ids
- gId, err := materialize.RoleId(meta.(*sqlx.DB), granteeName)
+ gId, err := materialize.RoleId(metaDb, granteeName)
if err != nil {
return diag.FromErr(err)
}
- tId, err := materialize.RoleId(meta.(*sqlx.DB), targetName)
+ tId, err := materialize.RoleId(metaDb, targetName)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, "DATABASE", gId, tId, "", "", privilege)
+ key := b.GrantKey(string(region), "DATABASE", gId, tId, "", "", privilege)
d.SetId(key)
return grantDefaultPrivilegeRead(ctx, d, meta)
@@ -67,7 +72,12 @@ func grantDatabaseDefaultPrivilegeDelete(ctx context.Context, d *schema.Resource
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "DATABASE", granteenName, targetName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "DATABASE", granteenName, targetName, privilege)
if err := b.Revoke(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_grant_database_default_privilege_test.go b/pkg/resources/resource_grant_database_default_privilege_test.go
index d510a52b..4795e68d 100644
--- a/pkg/resources/resource_grant_database_default_privilege_test.go
+++ b/pkg/resources/resource_grant_database_default_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantDatabaseDefaultPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantDatabaseDefaultPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantDatabaseDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" GRANT USAGE ON DATABASES TO "project_managers";`,
@@ -66,7 +65,7 @@ func TestResourceGrantDatabaseDefaultPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantDatabaseDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" REVOKE USAGE ON DATABASES FROM "project_managers";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantDatabaseDefaultPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_database_test.go b/pkg/resources/resource_grant_database_test.go
index fce9e5b0..301876fb 100644
--- a/pkg/resources/resource_grant_database_test.go
+++ b/pkg/resources/resource_grant_database_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantDatabaseCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantDatabaseCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantDatabase().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT CREATE ON DATABASE "materialize" TO "joe";`,
@@ -63,7 +62,7 @@ func TestResourceGrantDatabaseCreateEmail(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantDatabase().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT CREATE ON DATABASE "materialize" TO "joe@materialize.com";`,
@@ -82,7 +81,7 @@ func TestResourceGrantDatabaseDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantDatabase().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE CREATE ON DATABASE "materialize" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantDatabaseDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_default_privilege.go b/pkg/resources/resource_grant_default_privilege.go
index 51aa4dda..ceea38b4 100644
--- a/pkg/resources/resource_grant_default_privilege.go
+++ b/pkg/resources/resource_grant_default_privilege.go
@@ -11,7 +11,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"golang.org/x/exp/slices"
)
@@ -51,7 +50,12 @@ func grantDefaultPrivilegeRead(ctx context.Context, d *schema.ResourceData, meta
return nil
}
- privileges, err := materialize.ScanDefaultPrivilege(meta.(*sqlx.DB), key.objectType, key.granteeId, key.targetRoleId, key.databaseId, key.schemaId)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ privileges, err := materialize.ScanDefaultPrivilege(metaDb, key.objectType, key.granteeId, key.targetRoleId, key.databaseId, key.schemaId)
if err == sql.ErrNoRows {
log.Printf("[WARN] grant (%s) not found, removing from state file", d.Id())
d.SetId("")
@@ -70,6 +74,6 @@ func grantDefaultPrivilegeRead(ctx context.Context, d *schema.ResourceData, meta
d.SetId("")
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return nil
}
diff --git a/pkg/resources/resource_grant_default_privilege_test.go b/pkg/resources/resource_grant_default_privilege_test.go
index 1e694b60..69f82024 100644
--- a/pkg/resources/resource_grant_default_privilege_test.go
+++ b/pkg/resources/resource_grant_default_privilege_test.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -73,7 +72,7 @@ func TestParseDefaultPrivilegeIdErrorEmpty(t *testing.T) {
// Confirm id is updated with region for 0.4.0
// All resources share the same read function
func TestResourceGrantDefaultPrivilegeReadIdMigration(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -87,7 +86,7 @@ func TestResourceGrantDefaultPrivilegeReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("GRANT DEFAULT|CLUSTER|u1|u1|||USAGE")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
qp := `
WHERE mz_default_privileges.grantee = 'u1'
diff --git a/pkg/resources/resource_grant_materialized_view.go b/pkg/resources/resource_grant_materialized_view.go
index e61dce77..626c7155 100644
--- a/pkg/resources/resource_grant_materialized_view.go
+++ b/pkg/resources/resource_grant_materialized_view.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantMaterializedViewSchema = map[string]*schema.Schema{
@@ -32,6 +31,7 @@ var grantMaterializedViewSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantMaterializedView() *schema.Resource {
@@ -64,7 +64,12 @@ func grantMaterializedViewCreate(ctx context.Context, d *schema.ResourceData, me
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -72,17 +77,17 @@ func grantMaterializedViewCreate(ctx context.Context, d *schema.ResourceData, me
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -95,8 +100,13 @@ func grantMaterializedViewDelete(ctx context.Context, d *schema.ResourceData, me
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_materialized_view_test.go b/pkg/resources/resource_grant_materialized_view_test.go
index 864f08ef..7a42b55b 100644
--- a/pkg/resources/resource_grant_materialized_view_test.go
+++ b/pkg/resources/resource_grant_materialized_view_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantMaterializedViewCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -26,7 +25,7 @@ func TestResourceGrantMaterializedViewCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantMaterializedView().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT USAGE ON TABLE "database"."schema"."mview" TO "joe";`,
@@ -67,7 +66,7 @@ func TestResourceGrantMaterializedViewDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantMaterializedView().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE USAGE ON TABLE "database"."schema"."mview" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantMaterializedViewDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_role.go b/pkg/resources/resource_grant_role.go
index c43a5955..466fff5b 100644
--- a/pkg/resources/resource_grant_role.go
+++ b/pkg/resources/resource_grant_role.go
@@ -10,7 +10,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"golang.org/x/exp/slices"
)
@@ -27,6 +26,7 @@ var grantRoleSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantRole() *schema.Resource {
@@ -68,8 +68,13 @@ func grantRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}
return diag.FromErr(err)
}
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
// Scan role members
- roles, err := materialize.ScanRolePrivilege(meta.(*sqlx.DB), key.roleId, key.memberId)
+ roles, err := materialize.ScanRolePrivilege(metaDb, key.roleId, key.memberId)
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -85,7 +90,7 @@ func grantRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}
return diag.Errorf("role does contain member %s", key.memberId)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return nil
}
@@ -93,23 +98,28 @@ func grantRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface
roleName := d.Get("role_name").(string)
memberName := d.Get("member_name").(string)
- b := materialize.NewRolePrivilegeBuilder(meta.(*sqlx.DB), roleName, memberName)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewRolePrivilegeBuilder(metaDb, roleName, memberName)
if err := b.Grant(); err != nil {
return diag.FromErr(err)
}
- rId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ rId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- mId, err := materialize.RoleId(meta.(*sqlx.DB), memberName)
+ mId, err := materialize.RoleId(metaDb, memberName)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, rId, mId)
+ key := b.GrantKey(string(region), rId, mId)
d.SetId(key)
return grantRoleRead(ctx, d, meta)
@@ -119,7 +129,12 @@ func grantRoleDelete(ctx context.Context, d *schema.ResourceData, meta interface
roleName := d.Get("role_name").(string)
memberName := d.Get("member_name").(string)
- b := materialize.NewRolePrivilegeBuilder(meta.(*sqlx.DB), roleName, memberName)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewRolePrivilegeBuilder(metaDb, roleName, memberName)
if err := b.Revoke(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_grant_role_test.go b/pkg/resources/resource_grant_role_test.go
index 0c967c0b..53cc17ab 100644
--- a/pkg/resources/resource_grant_role_test.go
+++ b/pkg/resources/resource_grant_role_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantRolePrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -23,7 +22,7 @@ func TestResourceGrantRolePrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantRole().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT "role" TO "member";`,
@@ -52,7 +51,7 @@ func TestResourceGrantRolePrivilegeCreate(t *testing.T) {
// Confirm id is updated with region for 0.4.0
func TestResourceGrantRolePrivilegeReadIdMigration(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -65,7 +64,7 @@ func TestResourceGrantRolePrivilegeReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("ROLE MEMBER|u1|u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
testhelpers.MockRoleGrantScan(mock)
@@ -89,7 +88,7 @@ func TestResourceGrantRolePrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantRole().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE "role" FROM "member";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantRoleDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_schema.go b/pkg/resources/resource_grant_schema.go
index 14d3bd79..a586ba1e 100644
--- a/pkg/resources/resource_grant_schema.go
+++ b/pkg/resources/resource_grant_schema.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantSchemaSchema = map[string]*schema.Schema{
@@ -26,6 +25,7 @@ var grantSchemaSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantSchema() *schema.Resource {
@@ -56,7 +56,12 @@ func grantSchemaCreate(ctx context.Context, d *schema.ResourceData, meta interfa
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -64,17 +69,17 @@ func grantSchemaCreate(ctx context.Context, d *schema.ResourceData, meta interfa
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -86,8 +91,13 @@ func grantSchemaDelete(ctx context.Context, d *schema.ResourceData, meta interfa
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_schema_default_privilege.go b/pkg/resources/resource_grant_schema_default_privilege.go
index 7218e69d..b76c2a6b 100644
--- a/pkg/resources/resource_grant_schema_default_privilege.go
+++ b/pkg/resources/resource_grant_schema_default_privilege.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantSchemaDefaultPrivilegeSchema = map[string]*schema.Schema{
@@ -16,6 +15,7 @@ var grantSchemaDefaultPrivilegeSchema = map[string]*schema.Schema{
"target_role_name": TargetRoleNameSchema(),
"database_name": GrantDefaultDatabaseNameSchema(),
"privilege": PrivilegeSchema("SCHEMA"),
+ "region": RegionSchema(),
}
func GrantSchemaDefaultPrivilege() *schema.Resource {
@@ -39,7 +39,12 @@ func grantSchemaDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceDa
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "SCHEMA", granteeName, targetName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "SCHEMA", granteeName, targetName, privilege)
var database string
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
@@ -53,25 +58,25 @@ func grantSchemaDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceDa
}
// Query ids
- gId, err := materialize.RoleId(meta.(*sqlx.DB), granteeName)
+ gId, err := materialize.RoleId(metaDb, granteeName)
if err != nil {
return diag.FromErr(err)
}
- tId, err := materialize.RoleId(meta.(*sqlx.DB), targetName)
+ tId, err := materialize.RoleId(metaDb, targetName)
if err != nil {
return diag.FromErr(err)
}
var dId string
if database != "" {
- dId, err = materialize.DatabaseId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: database})
+ dId, err = materialize.DatabaseId(metaDb, materialize.MaterializeObject{Name: database})
if err != nil {
return diag.FromErr(err)
}
}
- key := b.GrantKey(utils.Region, "SCHEMA", gId, tId, dId, "", privilege)
+ key := b.GrantKey(string(region), "SCHEMA", gId, tId, dId, "", privilege)
d.SetId(key)
return grantDefaultPrivilegeRead(ctx, d, meta)
@@ -82,7 +87,12 @@ func grantSchemaDefaultPrivilegeDelete(ctx context.Context, d *schema.ResourceDa
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "SCHEMA", granteenName, targetName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "SCHEMA", granteenName, targetName, privilege)
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
b.DatabaseName(v.(string))
diff --git a/pkg/resources/resource_grant_schema_default_privilege_test.go b/pkg/resources/resource_grant_schema_default_privilege_test.go
index 4541aab1..08324671 100644
--- a/pkg/resources/resource_grant_schema_default_privilege_test.go
+++ b/pkg/resources/resource_grant_schema_default_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantSchemaDefaultPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantSchemaDefaultPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSchemaDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" GRANT USAGE ON SCHEMAS TO "project_managers";`,
@@ -66,7 +65,7 @@ func TestResourceGrantSchemaDefaultPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSchemaDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" REVOKE USAGE ON SCHEMAS FROM "project_managers";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantSchemaDefaultPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_schema_test.go b/pkg/resources/resource_grant_schema_test.go
index 2360757e..36677b0d 100644
--- a/pkg/resources/resource_grant_schema_test.go
+++ b/pkg/resources/resource_grant_schema_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantSchemaCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -25,7 +24,7 @@ func TestResourceGrantSchemaCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSchema().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT CREATE ON SCHEMA "database"."schema" TO "joe";`,
@@ -65,7 +64,7 @@ func TestResourceGrantSchemaDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSchema().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE CREATE ON SCHEMA "database"."schema" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantSchemaDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_secret.go b/pkg/resources/resource_grant_secret.go
index 787cef09..11a5bce5 100644
--- a/pkg/resources/resource_grant_secret.go
+++ b/pkg/resources/resource_grant_secret.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantSecretSchema = map[string]*schema.Schema{
@@ -32,6 +31,7 @@ var grantSecretSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantSecret() *schema.Resource {
@@ -64,7 +64,12 @@ func grantSecretCreate(ctx context.Context, d *schema.ResourceData, meta interfa
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -72,17 +77,17 @@ func grantSecretCreate(ctx context.Context, d *schema.ResourceData, meta interfa
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -95,8 +100,13 @@ func grantSecretDelete(ctx context.Context, d *schema.ResourceData, meta interfa
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_secret_default_privilege.go b/pkg/resources/resource_grant_secret_default_privilege.go
index 7d958e31..487f872e 100644
--- a/pkg/resources/resource_grant_secret_default_privilege.go
+++ b/pkg/resources/resource_grant_secret_default_privilege.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantSecretDefaultPrivilegeSchema = map[string]*schema.Schema{
@@ -17,6 +16,7 @@ var grantSecretDefaultPrivilegeSchema = map[string]*schema.Schema{
"database_name": GrantDefaultDatabaseNameSchema(),
"schema_name": GrantDefaultSchemaNameSchema(),
"privilege": PrivilegeSchema("SECRET"),
+ "region": RegionSchema(),
}
func GrantSecretDefaultPrivilege() *schema.Resource {
@@ -40,7 +40,12 @@ func grantSecretDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceDa
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "SECRET", granteeName, targetName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "SECRET", granteeName, targetName, privilege)
var database, schema string
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
@@ -59,32 +64,32 @@ func grantSecretDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceDa
}
// Query ids
- gId, err := materialize.RoleId(meta.(*sqlx.DB), granteeName)
+ gId, err := materialize.RoleId(metaDb, granteeName)
if err != nil {
return diag.FromErr(err)
}
- tId, err := materialize.RoleId(meta.(*sqlx.DB), targetName)
+ tId, err := materialize.RoleId(metaDb, targetName)
if err != nil {
return diag.FromErr(err)
}
var dId, sId string
if database != "" {
- dId, err = materialize.DatabaseId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: database})
+ dId, err = materialize.DatabaseId(metaDb, materialize.MaterializeObject{Name: database})
if err != nil {
return diag.FromErr(err)
}
}
if schema != "" {
- sId, err = materialize.SchemaId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: schema, DatabaseName: database})
+ sId, err = materialize.SchemaId(metaDb, materialize.MaterializeObject{Name: schema, DatabaseName: database})
if err != nil {
return diag.FromErr(err)
}
}
- key := b.GrantKey(utils.Region, "SECRET", gId, tId, dId, sId, privilege)
+ key := b.GrantKey(string(region), "SECRET", gId, tId, dId, sId, privilege)
d.SetId(key)
return grantDefaultPrivilegeRead(ctx, d, meta)
@@ -95,7 +100,12 @@ func grantSecretDefaultPrivilegeDelete(ctx context.Context, d *schema.ResourceDa
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "SECRET", granteenName, targetName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "SECRET", granteenName, targetName, privilege)
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
b.DatabaseName(v.(string))
diff --git a/pkg/resources/resource_grant_secret_default_privilege_test.go b/pkg/resources/resource_grant_secret_default_privilege_test.go
index 7bf159a8..d80650ac 100644
--- a/pkg/resources/resource_grant_secret_default_privilege_test.go
+++ b/pkg/resources/resource_grant_secret_default_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantSecretDefaultPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantSecretDefaultPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSecretDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" GRANT USAGE ON SECRETS TO "project_managers";`,
@@ -66,7 +65,7 @@ func TestResourceGrantSecretDefaultPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSecretDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" REVOKE USAGE ON SECRETS FROM "project_managers";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantSecretDefaultPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_secret_test.go b/pkg/resources/resource_grant_secret_test.go
index 54ea97e0..8d75040d 100644
--- a/pkg/resources/resource_grant_secret_test.go
+++ b/pkg/resources/resource_grant_secret_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantSecretCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -26,7 +25,7 @@ func TestResourceGrantSecretCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSecret().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT USAGE ON SECRET "database"."schema"."secret" TO "joe";`,
@@ -67,7 +66,7 @@ func TestResourceGrantSecretDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSecret().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE USAGE ON SECRET "database"."schema"."secret" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantSecretDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_source.go b/pkg/resources/resource_grant_source.go
index 06181dae..f9781ca7 100644
--- a/pkg/resources/resource_grant_source.go
+++ b/pkg/resources/resource_grant_source.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantSourceSchema = map[string]*schema.Schema{
@@ -32,6 +31,7 @@ var grantSourceSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantSource() *schema.Resource {
@@ -64,7 +64,12 @@ func grantSourceCreate(ctx context.Context, d *schema.ResourceData, meta interfa
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -72,17 +77,17 @@ func grantSourceCreate(ctx context.Context, d *schema.ResourceData, meta interfa
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -95,8 +100,13 @@ func grantSourceDelete(ctx context.Context, d *schema.ResourceData, meta interfa
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_source_test.go b/pkg/resources/resource_grant_source_test.go
index 8ddf865d..c69bb95f 100644
--- a/pkg/resources/resource_grant_source_test.go
+++ b/pkg/resources/resource_grant_source_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantSourceCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -26,7 +25,7 @@ func TestResourceGrantSourceCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSource().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT USAGE ON TABLE "database"."schema"."source" TO "joe";`,
@@ -67,7 +66,7 @@ func TestResourceGrantSourceDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSource().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE USAGE ON TABLE "database"."schema"."source" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantSourceDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_system_privilege.go b/pkg/resources/resource_grant_system_privilege.go
index a1450e02..04840e61 100644
--- a/pkg/resources/resource_grant_system_privilege.go
+++ b/pkg/resources/resource_grant_system_privilege.go
@@ -11,7 +11,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"golang.org/x/exp/slices"
)
@@ -24,6 +23,7 @@ var grantSystemPrivilegeSchema = map[string]*schema.Schema{
ForceNew: true,
ValidateFunc: validPrivileges("SYSTEM"),
},
+ "region": RegionSchema(),
}
func GrantSystemPrivilege() *schema.Resource {
@@ -60,6 +60,11 @@ func parseSystemPrivilegeKey(id string) (SystemPrivilegeKey, error) {
func grantSystemPrivilegeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
key, err := parseSystemPrivilegeKey(i)
if err != nil {
log.Printf("[WARN] malformed privilege (%s), removing from state file", d.Id())
@@ -67,7 +72,7 @@ func grantSystemPrivilegeRead(ctx context.Context, d *schema.ResourceData, meta
return nil
}
- p, err := materialize.ScanSystemPrivileges(meta.(*sqlx.DB))
+ p, err := materialize.ScanSystemPrivileges(metaDb)
if err == sql.ErrNoRows {
log.Printf("[WARN] grant (%s) not found, removing from state file", d.Id())
d.SetId("")
@@ -82,13 +87,17 @@ func grantSystemPrivilegeRead(ctx context.Context, d *schema.ResourceData, meta
privileges = append(privileges, pr.Privileges)
}
privilegeMap, err := materialize.MapGrantPrivileges(privileges)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
if !slices.Contains(privilegeMap[key.roleId], key.privilege) {
log.Printf("[DEBUG] %s object does not contain privilege %s", i, key.privilege)
// Remove id from state
d.SetId("")
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return nil
}
@@ -96,18 +105,23 @@ func grantSystemPrivilegeCreate(ctx context.Context, d *schema.ResourceData, met
roleName := d.Get("role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewSystemPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewSystemPrivilegeBuilder(metaDb, roleName, privilege)
if err := b.Grant(); err != nil {
return diag.FromErr(err)
}
- rId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ rId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, rId, privilege)
+ key := b.GrantKey(string(region), rId, privilege)
d.SetId(key)
return grantSystemPrivilegeRead(ctx, d, meta)
@@ -117,7 +131,12 @@ func grantSystemPrivilegeDelete(ctx context.Context, d *schema.ResourceData, met
roleName := d.Get("role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewSystemPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewSystemPrivilegeBuilder(metaDb, roleName, privilege)
if err := b.Revoke(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_grant_system_privilege_test.go b/pkg/resources/resource_grant_system_privilege_test.go
index 47e749c8..e46657d8 100644
--- a/pkg/resources/resource_grant_system_privilege_test.go
+++ b/pkg/resources/resource_grant_system_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantSystemPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -23,7 +22,7 @@ func TestResourceGrantSystemPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSystemPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT CREATEDB ON SYSTEM TO "role";`,
@@ -48,7 +47,7 @@ func TestResourceGrantSystemPrivilegeCreate(t *testing.T) {
// Confirm id is updated with region for 0.4.0
func TestResourceGrantSystemPrivilegeReadIdMigration(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -61,7 +60,7 @@ func TestResourceGrantSystemPrivilegeReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("GRANT SYSTEM|u1|CREATEDB")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
testhelpers.MockSystemGrantScan(mock)
@@ -85,7 +84,7 @@ func TestResourceGrantSystemPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantSystemPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE CREATEDB ON SYSTEM FROM "role";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantSystemPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_table.go b/pkg/resources/resource_grant_table.go
index 2feab1db..1feb1676 100644
--- a/pkg/resources/resource_grant_table.go
+++ b/pkg/resources/resource_grant_table.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantTableSchema = map[string]*schema.Schema{
@@ -32,6 +31,7 @@ var grantTableSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantTable() *schema.Resource {
@@ -64,7 +64,12 @@ func grantTableCreate(ctx context.Context, d *schema.ResourceData, meta interfac
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -72,17 +77,17 @@ func grantTableCreate(ctx context.Context, d *schema.ResourceData, meta interfac
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -95,8 +100,13 @@ func grantTableDelete(ctx context.Context, d *schema.ResourceData, meta interfac
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_table_default_privilege.go b/pkg/resources/resource_grant_table_default_privilege.go
index 108a436f..f61aba9e 100644
--- a/pkg/resources/resource_grant_table_default_privilege.go
+++ b/pkg/resources/resource_grant_table_default_privilege.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantTableDefaultPrivilegeSchema = map[string]*schema.Schema{
@@ -17,6 +16,7 @@ var grantTableDefaultPrivilegeSchema = map[string]*schema.Schema{
"database_name": GrantDefaultDatabaseNameSchema(),
"schema_name": GrantDefaultSchemaNameSchema(),
"privilege": PrivilegeSchema("TABLE"),
+ "region": RegionSchema(),
}
func GrantTableDefaultPrivilege() *schema.Resource {
@@ -40,7 +40,12 @@ func grantTableDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceDat
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "TABLE", granteeName, targetName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "TABLE", granteeName, targetName, privilege)
var database, schema string
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
@@ -59,32 +64,32 @@ func grantTableDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceDat
}
// Query ids
- gId, err := materialize.RoleId(meta.(*sqlx.DB), granteeName)
+ gId, err := materialize.RoleId(metaDb, granteeName)
if err != nil {
return diag.FromErr(err)
}
- tId, err := materialize.RoleId(meta.(*sqlx.DB), targetName)
+ tId, err := materialize.RoleId(metaDb, targetName)
if err != nil {
return diag.FromErr(err)
}
var dId, sId string
if database != "" {
- dId, err = materialize.DatabaseId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: database})
+ dId, err = materialize.DatabaseId(metaDb, materialize.MaterializeObject{Name: database})
if err != nil {
return diag.FromErr(err)
}
}
if schema != "" {
- sId, err = materialize.SchemaId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: schema, DatabaseName: database})
+ sId, err = materialize.SchemaId(metaDb, materialize.MaterializeObject{Name: schema, DatabaseName: database})
if err != nil {
return diag.FromErr(err)
}
}
- key := b.GrantKey(utils.Region, "TABLE", gId, tId, dId, sId, privilege)
+ key := b.GrantKey(string(region), "TABLE", gId, tId, dId, sId, privilege)
d.SetId(key)
return grantDefaultPrivilegeRead(ctx, d, meta)
@@ -95,7 +100,12 @@ func grantTableDefaultPrivilegeDelete(ctx context.Context, d *schema.ResourceDat
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "TABLE", granteenName, targetName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "TABLE", granteenName, targetName, privilege)
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
b.DatabaseName(v.(string))
diff --git a/pkg/resources/resource_grant_table_default_privilege_test.go b/pkg/resources/resource_grant_table_default_privilege_test.go
index caff35b9..e9f6d393 100644
--- a/pkg/resources/resource_grant_table_default_privilege_test.go
+++ b/pkg/resources/resource_grant_table_default_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantTableDefaultPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantTableDefaultPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantTableDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" GRANT USAGE ON TABLES TO "project_managers";`,
@@ -66,7 +65,7 @@ func TestResourceGrantTableDefaultPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantTableDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" REVOKE USAGE ON TABLES FROM "project_managers";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantTableDefaultPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_table_test.go b/pkg/resources/resource_grant_table_test.go
index 86e014ee..ce00537a 100644
--- a/pkg/resources/resource_grant_table_test.go
+++ b/pkg/resources/resource_grant_table_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantTableCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -26,7 +25,7 @@ func TestResourceGrantTableCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantTable().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT USAGE ON TABLE "database"."schema"."table" TO "joe";`,
@@ -67,7 +66,7 @@ func TestResourceGrantTableDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantTable().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE USAGE ON TABLE "database"."schema"."table" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantTableDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_test.go b/pkg/resources/resource_grant_test.go
index 222155a6..7e487cba 100644
--- a/pkg/resources/resource_grant_test.go
+++ b/pkg/resources/resource_grant_test.go
@@ -8,14 +8,13 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
// Confirm id is updated with region for 0.4.0
// All resources share the same read function
func TestResourceGrantPrivilegeReadIdMigration(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -29,7 +28,7 @@ func TestResourceGrantPrivilegeReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("GRANT|CLUSTER|u1|u1|CREATE")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_clusters.id = 'u1'`
testhelpers.MockClusterScan(mock, pp)
diff --git a/pkg/resources/resource_grant_type.go b/pkg/resources/resource_grant_type.go
index 60299631..eb085dc4 100644
--- a/pkg/resources/resource_grant_type.go
+++ b/pkg/resources/resource_grant_type.go
@@ -8,7 +8,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantTypeSchema = map[string]*schema.Schema{
@@ -32,6 +31,7 @@ var grantTypeSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantType() *schema.Resource {
@@ -64,7 +64,12 @@ func grantTypeCreate(ctx context.Context, d *schema.ResourceData, meta interface
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -72,17 +77,17 @@ func grantTypeCreate(ctx context.Context, d *schema.ResourceData, meta interface
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -95,8 +100,13 @@ func grantTypeDelete(ctx context.Context, d *schema.ResourceData, meta interface
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_type_default_privilege.go b/pkg/resources/resource_grant_type_default_privilege.go
index 59ab06d9..27d5d789 100644
--- a/pkg/resources/resource_grant_type_default_privilege.go
+++ b/pkg/resources/resource_grant_type_default_privilege.go
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantTypeDefaultPrivilegeSchema = map[string]*schema.Schema{
@@ -17,6 +16,7 @@ var grantTypeDefaultPrivilegeSchema = map[string]*schema.Schema{
"database_name": GrantDefaultDatabaseNameSchema(),
"schema_name": GrantDefaultSchemaNameSchema(),
"privilege": PrivilegeSchema("TYPE"),
+ "region": RegionSchema(),
}
func GrantTypeDefaultPrivilege() *schema.Resource {
@@ -40,7 +40,12 @@ func grantTypeDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceData
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "TYPE", granteeName, targetName, privilege)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "TYPE", granteeName, targetName, privilege)
var database, schema string
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
@@ -59,32 +64,32 @@ func grantTypeDefaultPrivilegeCreate(ctx context.Context, d *schema.ResourceData
}
// Query ids
- gId, err := materialize.RoleId(meta.(*sqlx.DB), granteeName)
+ gId, err := materialize.RoleId(metaDb, granteeName)
if err != nil {
return diag.FromErr(err)
}
- tId, err := materialize.RoleId(meta.(*sqlx.DB), targetName)
+ tId, err := materialize.RoleId(metaDb, targetName)
if err != nil {
return diag.FromErr(err)
}
var dId, sId string
if database != "" {
- dId, err = materialize.DatabaseId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: database})
+ dId, err = materialize.DatabaseId(metaDb, materialize.MaterializeObject{Name: database})
if err != nil {
return diag.FromErr(err)
}
}
if schema != "" {
- sId, err = materialize.SchemaId(meta.(*sqlx.DB), materialize.MaterializeObject{Name: schema, DatabaseName: database})
+ sId, err = materialize.SchemaId(metaDb, materialize.MaterializeObject{Name: schema, DatabaseName: database})
if err != nil {
return diag.FromErr(err)
}
}
- key := b.GrantKey(utils.Region, "TYPE", gId, tId, dId, sId, privilege)
+ key := b.GrantKey(string(region), "TYPE", gId, tId, dId, sId, privilege)
d.SetId(key)
return grantDefaultPrivilegeRead(ctx, d, meta)
@@ -95,7 +100,12 @@ func grantTypeDefaultPrivilegeDelete(ctx context.Context, d *schema.ResourceData
targetName := d.Get("target_role_name").(string)
privilege := d.Get("privilege").(string)
- b := materialize.NewDefaultPrivilegeBuilder(meta.(*sqlx.DB), "TYPE", granteenName, targetName, privilege)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewDefaultPrivilegeBuilder(metaDb, "TYPE", granteenName, targetName, privilege)
if v, ok := d.GetOk("database_name"); ok && v.(string) != "" {
b.DatabaseName(v.(string))
diff --git a/pkg/resources/resource_grant_type_default_privilege_test.go b/pkg/resources/resource_grant_type_default_privilege_test.go
index 3d9a19b8..2c7e2839 100644
--- a/pkg/resources/resource_grant_type_default_privilege_test.go
+++ b/pkg/resources/resource_grant_type_default_privilege_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantTypeDefaultPrivilegeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -24,7 +23,7 @@ func TestResourceGrantTypeDefaultPrivilegeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantTypeDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" GRANT USAGE ON TYPES TO "project_managers";`,
@@ -66,7 +65,7 @@ func TestResourceGrantTypeDefaultPrivilegeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantTypeDefaultPrivilege().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER DEFAULT PRIVILEGES FOR ROLE "developers" REVOKE USAGE ON TYPES FROM "project_managers";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantTypeDefaultPrivilegeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_type_test.go b/pkg/resources/resource_grant_type_test.go
index 1e74af3a..c888a65e 100644
--- a/pkg/resources/resource_grant_type_test.go
+++ b/pkg/resources/resource_grant_type_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantTypeCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -26,7 +25,7 @@ func TestResourceGrantTypeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantType().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`GRANT USAGE ON TYPE "database"."schema"."type" TO "joe";`,
@@ -67,7 +66,7 @@ func TestResourceGrantTypeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantType().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE USAGE ON TYPE "database"."schema"."type" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantTypeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_grant_view.go b/pkg/resources/resource_grant_view.go
index d83316c5..dbb6bf2c 100644
--- a/pkg/resources/resource_grant_view.go
+++ b/pkg/resources/resource_grant_view.go
@@ -7,7 +7,6 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var grantViewSchema = map[string]*schema.Schema{
@@ -31,6 +30,7 @@ var grantViewSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func GrantView() *schema.Resource {
@@ -63,7 +63,12 @@ func grantViewCreate(ctx context.Context, d *schema.ResourceData, meta interface
DatabaseName: databaseName,
}
- b := materialize.NewPrivilegeBuilder(meta.(*sqlx.DB), roleName, privilege, obj)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ b := materialize.NewPrivilegeBuilder(metaDb, roleName, privilege, obj)
// grant resource
if err := b.Grant(); err != nil {
@@ -71,17 +76,17 @@ func grantViewCreate(ctx context.Context, d *schema.ResourceData, meta interface
}
// set grant id
- roleId, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ roleId, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- i, err := materialize.ObjectId(meta.(*sqlx.DB), obj)
+ i, err := materialize.ObjectId(metaDb, obj)
if err != nil {
return diag.FromErr(err)
}
- key := b.GrantKey(utils.Region, i, roleId, privilege)
+ key := b.GrantKey(string(region), i, roleId, privilege)
d.SetId(key)
return grantRead(ctx, d, meta)
@@ -94,8 +99,13 @@ func grantViewDelete(ctx context.Context, d *schema.ResourceData, meta interface
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
b := materialize.NewPrivilegeBuilder(
- meta.(*sqlx.DB),
+ metaDb,
roleName,
privilege,
materialize.MaterializeObject{
diff --git a/pkg/resources/resource_grant_view_test.go b/pkg/resources/resource_grant_view_test.go
index 9c04662a..93a4d08a 100644
--- a/pkg/resources/resource_grant_view_test.go
+++ b/pkg/resources/resource_grant_view_test.go
@@ -8,12 +8,11 @@ import (
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
func TestResourceGrantViewCreate(t *testing.T) {
- utils.SetRegionFromHostname("localhost")
+ utils.SetDefaultRegion("aws/us-east-1")
r := require.New(t)
in := map[string]interface{}{
@@ -26,7 +25,8 @@ func TestResourceGrantViewCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantView().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
+
// Create
mock.ExpectExec(
`GRANT USAGE ON TABLE "database"."schema"."view" TO "joe";`,
@@ -67,7 +67,7 @@ func TestResourceGrantViewDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, GrantView().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`REVOKE USAGE ON TABLE "database"."schema"."view" FROM "joe";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := grantViewDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_index.go b/pkg/resources/resource_index.go
index 93352478..e509984c 100644
--- a/pkg/resources/resource_index.go
+++ b/pkg/resources/resource_index.go
@@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
- "github.com/jmoiron/sqlx"
)
var indexSchema = map[string]*schema.Schema{
@@ -71,6 +70,7 @@ var indexSchema = map[string]*schema.Schema{
Required: true,
ForceNew: true,
},
+ "region": RegionSchema(),
}
func Index() *schema.Resource {
@@ -92,7 +92,12 @@ func Index() *schema.Resource {
func indexRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanIndex(meta.(*sqlx.DB), utils.ExtractId(i))
+
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanIndex(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -100,7 +105,7 @@ func indexRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.IndexName.String); err != nil {
return diag.FromErr(err)
@@ -124,7 +129,7 @@ func indexRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
}
// Index columns
- indexColumns, err := materialize.ListIndexColumns(meta.(*sqlx.DB), utils.ExtractId(i))
+ indexColumns, err := materialize.ListIndexColumns(metaDb, utils.ExtractId(i))
if err != nil {
return diag.FromErr(err)
}
@@ -149,9 +154,14 @@ func indexCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
obj := d.Get("obj_name").([]interface{})[0].(map[string]interface{})
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{ObjectType: "INDEX", Name: indexName}
b := materialize.NewIndexBuilder(
- meta.(*sqlx.DB),
+ metaDb,
o,
indexDefault,
materialize.IdentifierSchemaStruct{
@@ -189,11 +199,11 @@ func indexCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
}
// set id
- i, err := materialize.IndexId(meta.(*sqlx.DB), indexName)
+ i, err := materialize.IndexId(metaDb, indexName)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return indexRead(ctx, d, meta)
}
@@ -202,9 +212,14 @@ func indexUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
indexName := d.Get("name").(string)
o := materialize.MaterializeObject{ObjectType: "INDEX", Name: indexName}
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -218,9 +233,14 @@ func indexDelete(ctx context.Context, d *schema.ResourceData, meta interface{})
obj := d.Get("obj_name").([]interface{})[0].(map[string]interface{})
name := d.Get("name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{ObjectType: "INDEX", Name: name}
b := materialize.NewIndexBuilder(
- meta.(*sqlx.DB),
+ metaDb,
o,
d.Get("default").(bool),
materialize.IdentifierSchemaStruct{
diff --git a/pkg/resources/resource_index_test.go b/pkg/resources/resource_index_test.go
index 96ca44b5..43fb851e 100644
--- a/pkg/resources/resource_index_test.go
+++ b/pkg/resources/resource_index_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -24,7 +24,7 @@ func TestResourceIndexCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Index().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE INDEX index IN CLUSTER cluster ON "database"."schema"."source" USING ARRANGEMENT \(\);`,
@@ -61,7 +61,7 @@ func TestResourceIndexReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_indexes.id = 'u1' AND mz_objects.type IN \('source', 'view', 'materialized-view'\)`
testhelpers.MockIndexScan(mock, pp)
@@ -91,7 +91,7 @@ func TestResourceIndexDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Index().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP INDEX "database"."schema"."index" RESTRICT;`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := indexDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_materialized_view.go b/pkg/resources/resource_materialized_view.go
index 314d5763..43b6f5d0 100644
--- a/pkg/resources/resource_materialized_view.go
+++ b/pkg/resources/resource_materialized_view.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var GrantDefinition = "Manages the privileges on a Materailize %[1]s for roles."
@@ -42,6 +41,7 @@ var materializedViewSchema = map[string]*schema.Schema{
ForceNew: true,
},
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func MaterializedView() *schema.Resource {
@@ -64,7 +64,11 @@ func MaterializedView() *schema.Resource {
func materializedViewRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanMaterializedView(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanMaterializedView(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -72,7 +76,7 @@ func materializedViewRead(ctx context.Context, d *schema.ResourceData, meta inte
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.MaterializedViewName.String); err != nil {
return diag.FromErr(err)
@@ -111,8 +115,12 @@ func materializedViewCreate(ctx context.Context, d *schema.ResourceData, meta in
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "MATERIALIZED VIEW", Name: materializedViewName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewMaterializedViewBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewMaterializedViewBuilder(metaDb, o)
if v, ok := d.GetOk("cluster_name"); ok && v.(string) != "" {
b.ClusterName(v.(string))
@@ -134,7 +142,7 @@ func materializedViewCreate(ctx context.Context, d *schema.ResourceData, meta in
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -145,7 +153,7 @@ func materializedViewCreate(ctx context.Context, d *schema.ResourceData, meta in
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -155,11 +163,11 @@ func materializedViewCreate(ctx context.Context, d *schema.ResourceData, meta in
}
// set id
- i, err := materialize.MaterializedViewId(meta.(*sqlx.DB), o)
+ i, err := materialize.MaterializedViewId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return materializedViewRead(ctx, d, meta)
}
@@ -169,12 +177,16 @@ func materializedViewUpdate(ctx context.Context, d *schema.ResourceData, meta in
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "MATERIALIZED VIEW", Name: materializedViewName, SchemaName: schemaName, DatabaseName: databaseName}
if d.HasChange("name") {
oldName, newMaterializedViewName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "MATERIALIZED VIEW", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewMaterializedViewBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewMaterializedViewBuilder(metaDb, o)
if err := b.Rename(newMaterializedViewName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -182,7 +194,7 @@ func materializedViewUpdate(ctx context.Context, d *schema.ResourceData, meta in
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -191,7 +203,7 @@ func materializedViewUpdate(ctx context.Context, d *schema.ResourceData, meta in
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -206,8 +218,12 @@ func materializedViewDelete(ctx context.Context, d *schema.ResourceData, meta an
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: materializedViewName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewMaterializedViewBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewMaterializedViewBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_materialized_view_test.go b/pkg/resources/resource_materialized_view_test.go
index a130c0af..e0e92711 100644
--- a/pkg/resources/resource_materialized_view_test.go
+++ b/pkg/resources/resource_materialized_view_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -26,7 +26,7 @@ func TestResourceMaterializedViewCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, MaterializedView().Schema, inMaterializedView)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE MATERIALIZED VIEW "database"."schema"."materialized_view" IN CLUSTER "cluster" WITH \(ASSERT NOT NULL "column_1", ASSERT NOT NULL "column_2"\) AS SELECT 1 FROM 1;`,
@@ -55,7 +55,7 @@ func TestResourceMaterializedViewReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_materialized_views.id = 'u1'`
testhelpers.MockMaterializeViewScan(mock, pp)
@@ -79,7 +79,7 @@ func TestResourceMaterializedViewUpdate(t *testing.T) {
d.Set("name", "old_materialized_view")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER MATERIALIZED VIEW "database"."schema"."" RENAME TO "materialized_view";`).WillReturnResult(sqlmock.NewResult(1, 1))
// Query Params
@@ -103,7 +103,7 @@ func TestResourceMaterializedViewDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, MaterializedView().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP MATERIALIZED VIEW "database"."schema"."materialized_view";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := materializedViewDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_role.go b/pkg/resources/resource_role.go
index b1b0ee96..5c7a2a7b 100644
--- a/pkg/resources/resource_role.go
+++ b/pkg/resources/resource_role.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var roleSchema = map[string]*schema.Schema{
@@ -22,6 +21,7 @@ var roleSchema = map[string]*schema.Schema{
Type: schema.TypeBool,
Computed: true,
},
+ "region": RegionSchema(),
}
func Role() *schema.Resource {
@@ -43,7 +43,12 @@ func Role() *schema.Resource {
func roleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanRole(meta.(*sqlx.DB), utils.ExtractId(i))
+
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanRole(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -51,7 +56,7 @@ func roleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.RoleName.String); err != nil {
return diag.FromErr(err)
@@ -76,8 +81,13 @@ func roleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
func roleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
roleName := d.Get("name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{ObjectType: "ROLE", Name: roleName}
- b := materialize.NewRoleBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewRoleBuilder(metaDb, o)
if v, ok := d.GetOk("inherit"); ok && v.(bool) {
b.Inherit()
@@ -90,7 +100,7 @@ func roleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -100,11 +110,11 @@ func roleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
}
// set id
- i, err := materialize.RoleId(meta.(*sqlx.DB), roleName)
+ i, err := materialize.RoleId(metaDb, roleName)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return roleRead(ctx, d, meta)
}
@@ -114,9 +124,14 @@ func roleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
o := materialize.MaterializeObject{ObjectType: "ROLE", Name: roleName}
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -129,8 +144,13 @@ func roleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
func roleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
roleName := d.Get("name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
o := materialize.MaterializeObject{ObjectType: "ROLE", Name: roleName}
- b := materialize.NewRoleBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewRoleBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_role_test.go b/pkg/resources/resource_role_test.go
index dfade28b..90ccf0c3 100644
--- a/pkg/resources/resource_role_test.go
+++ b/pkg/resources/resource_role_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestResourceRoleCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Role().Schema, inRole)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE ROLE "role" INHERIT;`,
@@ -51,7 +51,7 @@ func TestResourceRoleReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_roles.id = 'u1'`
testhelpers.MockRoleScan(mock, pp)
@@ -72,7 +72,7 @@ func TestResourceRoleDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Role().Schema, inRole)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP ROLE "role";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := roleDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_schema.go b/pkg/resources/resource_schema.go
index 46bd936a..3edc7442 100644
--- a/pkg/resources/resource_schema.go
+++ b/pkg/resources/resource_schema.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var schemaSchema = map[string]*schema.Schema{
@@ -19,6 +18,7 @@ var schemaSchema = map[string]*schema.Schema{
"qualified_sql_name": QualifiedNameSchema("schema"),
"comment": CommentSchema(false),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func Schema() *schema.Resource {
@@ -40,7 +40,11 @@ func Schema() *schema.Resource {
func schemaRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanSchema(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanSchema(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -48,7 +52,7 @@ func schemaRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.SchemaName.String); err != nil {
return diag.FromErr(err)
@@ -78,8 +82,12 @@ func schemaCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SCHEMA", Name: schemaName, DatabaseName: databaseName}
- b := materialize.NewSchemaBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSchemaBuilder(metaDb, o)
// create resource
if err := b.Create(); err != nil {
@@ -88,7 +96,7 @@ func schemaCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -99,7 +107,7 @@ func schemaCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -109,11 +117,11 @@ func schemaCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
}
// set id
- i, err := materialize.SchemaId(meta.(*sqlx.DB), o)
+ i, err := materialize.SchemaId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return schemaRead(ctx, d, meta)
}
@@ -122,8 +130,12 @@ func schemaUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SCHEMA", Name: schemaName, DatabaseName: databaseName}
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
@@ -134,7 +146,7 @@ func schemaUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -148,8 +160,12 @@ func schemaDelete(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: schemaName, DatabaseName: databaseName}
- b := materialize.NewSchemaBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSchemaBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_schema_test.go b/pkg/resources/resource_schema_test.go
index 53441dac..0bfd292c 100644
--- a/pkg/resources/resource_schema_test.go
+++ b/pkg/resources/resource_schema_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -22,7 +22,7 @@ func TestResourceSchemaCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Schema().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE SCHEMA "database"."schema";`,
@@ -55,7 +55,7 @@ func TestResourceSchemaReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_schemas.id = 'u1'`
testhelpers.MockSchemaScan(mock, pp)
@@ -80,7 +80,7 @@ func TestResourceSchemaDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Schema().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP SCHEMA "database"."schema";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := schemaDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_secret.go b/pkg/resources/resource_secret.go
index aafa3d0c..f1cad480 100644
--- a/pkg/resources/resource_secret.go
+++ b/pkg/resources/resource_secret.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var secretSchema = map[string]*schema.Schema{
@@ -26,6 +25,7 @@ var secretSchema = map[string]*schema.Schema{
Sensitive: true,
},
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func Secret() *schema.Resource {
@@ -48,7 +48,11 @@ func Secret() *schema.Resource {
func secretRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanSecret(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanSecret(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -56,7 +60,7 @@ func secretRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.SecretName.String); err != nil {
return diag.FromErr(err)
@@ -91,8 +95,12 @@ func secretCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SECRET", Name: secretName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSecretBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSecretBuilder(metaDb, o)
if v, ok := d.GetOk("value"); ok {
b.Value(v.(string))
@@ -105,7 +113,7 @@ func secretCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -116,7 +124,7 @@ func secretCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -126,11 +134,11 @@ func secretCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
}
// set id
- i, err := materialize.SecretId(meta.(*sqlx.DB), o)
+ i, err := materialize.SecretId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return secretRead(ctx, d, meta)
}
@@ -140,13 +148,17 @@ func secretUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SECRET", Name: secretName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSecretBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSecretBuilder(metaDb, o)
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "SECRET", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSecretBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSecretBuilder(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -161,7 +173,7 @@ func secretUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -170,7 +182,7 @@ func secretUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -185,8 +197,12 @@ func secretDelete(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: secretName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSecretBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSecretBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_secret_test.go b/pkg/resources/resource_secret_test.go
index db99653e..4e504403 100644
--- a/pkg/resources/resource_secret_test.go
+++ b/pkg/resources/resource_secret_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -24,7 +24,8 @@ func TestResourceSecretCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Secret().Schema, inSecret)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
+
// Create
mock.ExpectExec(
`CREATE SECRET "database"."schema"."secret" AS 'value';`,
@@ -53,7 +54,7 @@ func TestResourceSecretReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_secrets.id = 'u1'`
testhelpers.MockSecretScan(mock, pp)
@@ -78,7 +79,7 @@ func TestResourceSecretUpdate(t *testing.T) {
d.Set("value", "old_value")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER SECRET "database"."schema"."" RENAME TO "secret";`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`ALTER SECRET "database"."schema"."old_secret" AS 'value';`).WillReturnResult(sqlmock.NewResult(1, 1))
@@ -104,7 +105,7 @@ func TestResourceSecretDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Secret().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP SECRET "database"."schema"."secret";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := secretDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_sink.go b/pkg/resources/resource_sink.go
index 29716992..d27454ba 100644
--- a/pkg/resources/resource_sink.go
+++ b/pkg/resources/resource_sink.go
@@ -9,13 +9,16 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func sinkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanSink(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanSink(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -23,7 +26,7 @@ func sinkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.SinkName.String); err != nil {
return diag.FromErr(err)
@@ -66,13 +69,17 @@ func sinkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SINK", Name: sinkName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSink(meta.(*sqlx.DB), o)
+ b := materialize.NewSink(metaDb, o)
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "SINK", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSink(meta.(*sqlx.DB), o)
+ b := materialize.NewSink(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -87,7 +94,7 @@ func sinkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -96,7 +103,7 @@ func sinkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -111,8 +118,12 @@ func sinkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) d
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: sinkName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSink(meta.(*sqlx.DB), o)
+ b := materialize.NewSink(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_sink_kafka.go b/pkg/resources/resource_sink_kafka.go
index 97a27200..05808177 100644
--- a/pkg/resources/resource_sink_kafka.go
+++ b/pkg/resources/resource_sink_kafka.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
- "github.com/jmoiron/sqlx"
)
var sinkKafkaSchema = map[string]*schema.Schema{
@@ -84,6 +83,7 @@ var sinkKafkaSchema = map[string]*schema.Schema{
ForceNew: true,
Default: false,
},
+ "region": RegionSchema(),
}
func SinkKafka() *schema.Resource {
@@ -108,8 +108,12 @@ func sinkKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) diag
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SINK", Name: sinkName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSinkKafkaBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSinkKafkaBuilder(metaDb, o)
if v, ok := d.GetOk("cluster_name"); ok {
b.ClusterName(v.(string))
@@ -167,7 +171,7 @@ func sinkKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) diag
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -178,7 +182,7 @@ func sinkKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) diag
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -188,11 +192,11 @@ func sinkKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) diag
}
// set id
- i, err := materialize.SinkId(meta.(*sqlx.DB), o)
+ i, err := materialize.SinkId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return sinkRead(ctx, d, meta)
}
diff --git a/pkg/resources/resource_sink_kafka_test.go b/pkg/resources/resource_sink_kafka_test.go
index 05e9faeb..abd1ac13 100644
--- a/pkg/resources/resource_sink_kafka_test.go
+++ b/pkg/resources/resource_sink_kafka_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -94,7 +94,7 @@ func TestResourceSinkKafkaCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, SinkKafka().Schema, inSinkKafka)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE SINK "database"."schema"."sink"
diff --git a/pkg/resources/resource_sink_test.go b/pkg/resources/resource_sink_test.go
index d20775ca..e91fc7a5 100644
--- a/pkg/resources/resource_sink_test.go
+++ b/pkg/resources/resource_sink_test.go
@@ -6,8 +6,8 @@ import (
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -20,7 +20,7 @@ func TestResourceSinkReadIdMigration(t *testing.T) {
// Set current state
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_sinks.id = 'u1'`
testhelpers.MockSinkScan(mock, pp)
@@ -45,7 +45,7 @@ func TestResourceSinkUpdate(t *testing.T) {
d.Set("size", "medium")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER SINK "database"."schema"."" RENAME TO "sink";`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`ALTER SINK "database"."schema"."old_sink" SET \(SIZE = 'small'\);`).WillReturnResult(sqlmock.NewResult(1, 1))
@@ -70,7 +70,7 @@ func TestResourceSinkDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, SinkKafka().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP SINK "database"."schema"."sink";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := sinkDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_source.go b/pkg/resources/resource_source.go
index 12a115ad..c00fd705 100644
--- a/pkg/resources/resource_source.go
+++ b/pkg/resources/resource_source.go
@@ -9,13 +9,16 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
func sourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanSource(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanSource(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -23,7 +26,7 @@ func sourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.SourceName.String); err != nil {
return diag.FromErr(err)
@@ -59,7 +62,7 @@ func sourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) d
}
// Subsources
- deps, err := materialize.ListDependencies(meta.(*sqlx.DB), utils.ExtractId(i), "source")
+ deps, err := materialize.ListDependencies(metaDb, utils.ExtractId(i), "source")
if err != nil {
return diag.FromErr(err)
}
@@ -87,13 +90,17 @@ func sourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Di
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: sourceName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSource(meta.(*sqlx.DB), o)
+ b := materialize.NewSource(metaDb, o)
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSource(meta.(*sqlx.DB), o)
+ b := materialize.NewSource(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -108,7 +115,7 @@ func sourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Di
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -117,7 +124,7 @@ func sourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Di
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -132,8 +139,12 @@ func sourceDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Di
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: sourceName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSource(meta.(*sqlx.DB), o)
+ b := materialize.NewSource(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_source_kafka.go b/pkg/resources/resource_source_kafka.go
index ebf77526..a42c56d7 100644
--- a/pkg/resources/resource_source_kafka.go
+++ b/pkg/resources/resource_source_kafka.go
@@ -9,7 +9,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var sourceKafkaSchema = map[string]*schema.Schema{
@@ -141,6 +140,7 @@ var sourceKafkaSchema = map[string]*schema.Schema{
"expose_progress": IdentifierSchema("expose_progress", "The name of the progress subsource for the source. If this is not specified, the subsource will be named `_progress`.", false),
"subsource": SubsourceSchema(),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func SourceKafka() *schema.Resource {
@@ -165,8 +165,12 @@ func sourceKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) di
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: sourceName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSourceKafkaBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSourceKafkaBuilder(metaDb, o)
if v, ok := d.GetOk("cluster_name"); ok {
b.ClusterName(v.(string))
@@ -266,7 +270,7 @@ func sourceKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) di
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -277,7 +281,7 @@ func sourceKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) di
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -287,11 +291,11 @@ func sourceKafkaCreate(ctx context.Context, d *schema.ResourceData, meta any) di
}
// set id
- i, err := materialize.SourceId(meta.(*sqlx.DB), o)
+ i, err := materialize.SourceId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return sourceRead(ctx, d, meta)
}
diff --git a/pkg/resources/resource_source_kafka_test.go b/pkg/resources/resource_source_kafka_test.go
index 0e008b16..68f4f3bc 100644
--- a/pkg/resources/resource_source_kafka_test.go
+++ b/pkg/resources/resource_source_kafka_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -57,7 +57,7 @@ func TestResourceSourceKafkaCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, SourceKafka().Schema, inSourceKafka)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE SOURCE "database"."schema"."source"
diff --git a/pkg/resources/resource_source_load_generator.go b/pkg/resources/resource_source_load_generator.go
index 216661bf..37ec4328 100644
--- a/pkg/resources/resource_source_load_generator.go
+++ b/pkg/resources/resource_source_load_generator.go
@@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
- "github.com/jmoiron/sqlx"
)
var tick_interval = &schema.Schema{
@@ -113,6 +112,7 @@ var sourceLoadgenSchema = map[string]*schema.Schema{
"expose_progress": IdentifierSchema("expose_progress", "The name of the progress subsource for the source. If this is not specified, the subsource will be named `_progress`.", false),
"subsource": SubsourceSchema(),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func SourceLoadgen() *schema.Resource {
@@ -137,8 +137,12 @@ func sourceLoadgenCreate(ctx context.Context, d *schema.ResourceData, meta any)
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: sourceName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSourceLoadgenBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSourceLoadgenBuilder(metaDb, o)
if v, ok := d.GetOk("cluster_name"); ok {
b.ClusterName(v.(string))
@@ -184,7 +188,7 @@ func sourceLoadgenCreate(ctx context.Context, d *schema.ResourceData, meta any)
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -195,7 +199,7 @@ func sourceLoadgenCreate(ctx context.Context, d *schema.ResourceData, meta any)
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -205,11 +209,11 @@ func sourceLoadgenCreate(ctx context.Context, d *schema.ResourceData, meta any)
}
// set id
- i, err := materialize.SourceId(meta.(*sqlx.DB), o)
+ i, err := materialize.SourceId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return sourceRead(ctx, d, meta)
}
diff --git a/pkg/resources/resource_source_load_generator_test.go b/pkg/resources/resource_source_load_generator_test.go
index 7e9bb4ed..4f6a85b4 100644
--- a/pkg/resources/resource_source_load_generator_test.go
+++ b/pkg/resources/resource_source_load_generator_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -31,7 +31,7 @@ func TestResourceSourceLoadgenCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, SourceLoadgen().Schema, inSourceLoadgen)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE SOURCE "database"."schema"."source"
diff --git a/pkg/resources/resource_source_postgres.go b/pkg/resources/resource_source_postgres.go
index 6fba1493..e7a10953 100644
--- a/pkg/resources/resource_source_postgres.go
+++ b/pkg/resources/resource_source_postgres.go
@@ -9,7 +9,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var sourcePostgresSchema = map[string]*schema.Schema{
@@ -66,6 +65,7 @@ var sourcePostgresSchema = map[string]*schema.Schema{
"expose_progress": IdentifierSchema("expose_progress", "The name of the progress subsource for the source. If this is not specified, the subsource will be named `_progress`.", false),
"subsource": SubsourceSchema(),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func SourcePostgres() *schema.Resource {
@@ -90,8 +90,12 @@ func sourcePostgresCreate(ctx context.Context, d *schema.ResourceData, meta any)
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: sourceName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSourcePostgresBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSourcePostgresBuilder(metaDb, o)
if v, ok := d.GetOk("cluster_name"); ok {
b.ClusterName(v.(string))
@@ -137,7 +141,7 @@ func sourcePostgresCreate(ctx context.Context, d *schema.ResourceData, meta any)
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -148,7 +152,7 @@ func sourcePostgresCreate(ctx context.Context, d *schema.ResourceData, meta any)
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -158,11 +162,11 @@ func sourcePostgresCreate(ctx context.Context, d *schema.ResourceData, meta any)
}
// set id
- i, err := materialize.SourceId(meta.(*sqlx.DB), o)
+ i, err := materialize.SourceId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return sourceRead(ctx, d, meta)
}
@@ -172,13 +176,17 @@ func sourcePostgresUpdate(ctx context.Context, d *schema.ResourceData, meta any)
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: sourceName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSource(meta.(*sqlx.DB), o)
+ b := materialize.NewSource(metaDb, o)
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSource(meta.(*sqlx.DB), o)
+ b := materialize.NewSource(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
}
@@ -193,7 +201,7 @@ func sourcePostgresUpdate(ctx context.Context, d *schema.ResourceData, meta any)
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -225,7 +233,7 @@ func sourcePostgresUpdate(ctx context.Context, d *schema.ResourceData, meta any)
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_source_postgres_test.go b/pkg/resources/resource_source_postgres_test.go
index 246caa59..1aa9f9f3 100644
--- a/pkg/resources/resource_source_postgres_test.go
+++ b/pkg/resources/resource_source_postgres_test.go
@@ -6,10 +6,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -38,7 +38,7 @@ func TestResourceSourcePostgresCreateTable(t *testing.T) {
d := schema.TestResourceDataRaw(t, SourcePostgres().Schema, inSourcePostgresTable)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE SOURCE "database"."schema"."source" IN CLUSTER "cluster" FROM POSTGRES CONNECTION "materialize"."public"."pg_connection" \(PUBLICATION 'mz_source', TEXT COLUMNS \(table.unsupported_type_1\)\) FOR TABLES \(name1 AS alias, name2 AS name2\) WITH \(SIZE = 'small'\);`,
@@ -83,7 +83,7 @@ func TestResourceSourcePostgresCreateSchema(t *testing.T) {
d := schema.TestResourceDataRaw(t, SourcePostgres().Schema, inSourcePostgresSchema)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE SOURCE "database"."schema"."source" IN CLUSTER "cluster" FROM POSTGRES CONNECTION "materialize"."public"."pg_connection" \(PUBLICATION 'mz_source', TEXT COLUMNS \(table.unsupported_type_1\)\) FOR SCHEMAS \(schema1, schema2\) WITH \(SIZE = 'small'\);`,
@@ -116,7 +116,7 @@ func TestResourceSourcePostgresUpdate(t *testing.T) {
d.Set("size", "large")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER SOURCE "database"."schema"."" RENAME TO "source"`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`ALTER SOURCE "database"."schema"."old_source" SET \(SIZE = 'small'\)`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`ALTER SOURCE "database"."schema"."old_source" ADD SUBSOURCE "name1" AS "alias", "name2"`).WillReturnResult(sqlmock.NewResult(1, 1))
diff --git a/pkg/resources/resource_source_test.go b/pkg/resources/resource_source_test.go
index f4aee7e8..e4670905 100644
--- a/pkg/resources/resource_source_test.go
+++ b/pkg/resources/resource_source_test.go
@@ -6,8 +6,8 @@ import (
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -20,7 +20,7 @@ func TestResourceSourceReadIdMigration(t *testing.T) {
// Set current state
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_sources.id = 'u1'`
testhelpers.MockSourceScan(mock, pp)
@@ -49,7 +49,7 @@ func TestResourceSourceUpdate(t *testing.T) {
d.Set("size", "medium")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER SOURCE "database"."schema"."" RENAME TO "source";`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`ALTER SOURCE "database"."schema"."old_source" SET \(SIZE = 'small'\);`).WillReturnResult(sqlmock.NewResult(1, 1))
// Query Params
@@ -77,7 +77,7 @@ func TestResourceSourceDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, SourcePostgres().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP SOURCE "database"."schema"."source"`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := sourceDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_source_webhook.go b/pkg/resources/resource_source_webhook.go
index d3c7a0e2..3faddc53 100644
--- a/pkg/resources/resource_source_webhook.go
+++ b/pkg/resources/resource_source_webhook.go
@@ -9,7 +9,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
- "github.com/jmoiron/sqlx"
)
var sourceWebhookSchema = map[string]*schema.Schema{
@@ -150,6 +149,7 @@ var sourceWebhookSchema = map[string]*schema.Schema{
},
"subsource": SubsourceSchema(),
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func SourceWebhook() *schema.Resource {
@@ -177,8 +177,12 @@ func sourceWebhookCreate(ctx context.Context, d *schema.ResourceData, meta inter
clusterName := d.Get("cluster_name").(string)
bodyFormat := d.Get("body_format").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "SOURCE", Name: sourceName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewSourceWebhookBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewSourceWebhookBuilder(metaDb, o)
b.ClusterName(clusterName).
BodyFormat(bodyFormat).
@@ -248,7 +252,7 @@ func sourceWebhookCreate(ctx context.Context, d *schema.ResourceData, meta inter
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -259,7 +263,7 @@ func sourceWebhookCreate(ctx context.Context, d *schema.ResourceData, meta inter
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -269,11 +273,11 @@ func sourceWebhookCreate(ctx context.Context, d *schema.ResourceData, meta inter
}
// Set id
- i, err := materialize.SourceId(meta.(*sqlx.DB), o)
+ i, err := materialize.SourceId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return sourceRead(ctx, d, meta)
}
diff --git a/pkg/resources/resource_source_webhook_test.go b/pkg/resources/resource_source_webhook_test.go
index adf81376..f7a2130c 100644
--- a/pkg/resources/resource_source_webhook_test.go
+++ b/pkg/resources/resource_source_webhook_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -45,7 +45,7 @@ func TestResourceSourceWebhookCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, SourceWebhook().Schema, inSourceWebhook)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(
`CREATE SOURCE "database"."schema"."webhook_source" IN CLUSTER "cluster" FROM WEBHOOK BODY FORMAT JSON INCLUDE HEADERS CHECK \( WITH \(BODY AS bytes\, HEADERS AS headers\) check_expression\);`,
diff --git a/pkg/resources/resource_table.go b/pkg/resources/resource_table.go
index 4f51df72..24d08da6 100644
--- a/pkg/resources/resource_table.go
+++ b/pkg/resources/resource_table.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var tableSchema = map[string]*schema.Schema{
@@ -65,6 +64,7 @@ var tableSchema = map[string]*schema.Schema{
ForceNew: true,
},
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func Table() *schema.Resource {
@@ -87,7 +87,11 @@ func Table() *schema.Resource {
func tableRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanTable(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanTable(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -95,7 +99,7 @@ func tableRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.TableName.String); err != nil {
return diag.FromErr(err)
@@ -123,7 +127,7 @@ func tableRead(ctx context.Context, d *schema.ResourceData, meta interface{}) di
}
// Table columns
- tableColumns, err := materialize.ListTableColumns(meta.(*sqlx.DB), utils.ExtractId(i))
+ tableColumns, err := materialize.ListTableColumns(metaDb, utils.ExtractId(i))
if err != nil {
log.Print("[DEBUG] cannot query list tables")
return diag.FromErr(err)
@@ -151,8 +155,12 @@ func tableCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "TABLE", Name: tableName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewTableBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewTableBuilder(metaDb, o)
if v, ok := d.GetOk("column"); ok {
columns := materialize.GetTableColumnStruct(v.([]interface{}))
@@ -166,7 +174,7 @@ func tableCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -177,7 +185,7 @@ func tableCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -189,7 +197,7 @@ func tableCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
// column comment
if v, ok := d.GetOk("column"); ok {
columns := materialize.GetTableColumnStruct(v.([]interface{}))
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
for _, c := range columns {
if c.Comment != "" {
@@ -203,13 +211,13 @@ func tableCreate(ctx context.Context, d *schema.ResourceData, meta interface{})
}
// set id
- i, err := materialize.TableId(meta.(*sqlx.DB), o)
+ i, err := materialize.TableId(metaDb, o)
if err != nil {
log.Printf("[DEBUG] cannot query table: %s", o.QualifiedName())
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return tableRead(ctx, d, meta)
}
@@ -219,12 +227,16 @@ func tableUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "TABLE", Name: tableName, SchemaName: schemaName, DatabaseName: databaseName}
if d.HasChange("name") {
oldName, newName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "TABLE", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewTableBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewTableBuilder(metaDb, o)
if err := b.Rename(newName.(string)); err != nil {
return diag.FromErr(err)
@@ -233,7 +245,7 @@ func tableUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -242,7 +254,7 @@ func tableUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -261,7 +273,7 @@ func tableUpdate(ctx context.Context, d *schema.ResourceData, meta interface{})
// Check specifically if the column comment has changed.
if newCol["comment"] != oldCol["comment"] {
// Apply the comment change
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
colName := newCol["name"].(string)
colComment := newCol["comment"].(string)
if err := comment.Column(colName, colComment); err != nil {
@@ -279,8 +291,12 @@ func tableDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Dia
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: tableName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewTableBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewTableBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_table_test.go b/pkg/resources/resource_table_test.go
index f9098216..c99462f6 100644
--- a/pkg/resources/resource_table_test.go
+++ b/pkg/resources/resource_table_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -32,7 +32,7 @@ func TestResourceTableCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Table().Schema, inTable)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(`
CREATE TABLE "database"."schema"."table" \(column text NOT NULL DEFAULT NULL\);
@@ -72,7 +72,7 @@ func TestResourceTableReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_tables.id = 'u1'`
testhelpers.MockTableScan(mock, pp)
@@ -102,7 +102,8 @@ func TestResourceTableDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Table().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
+
mock.ExpectExec(`DROP TABLE "database"."schema"."table";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := tableDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_type.go b/pkg/resources/resource_type.go
index a7f1173d..293c6f87 100644
--- a/pkg/resources/resource_type.go
+++ b/pkg/resources/resource_type.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var typeSchema = map[string]*schema.Schema{
@@ -88,6 +87,7 @@ var typeSchema = map[string]*schema.Schema{
Computed: true,
},
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func Type() *schema.Resource {
@@ -110,7 +110,11 @@ func Type() *schema.Resource {
func typeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanType(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanType(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -118,7 +122,7 @@ func typeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.TypeName.String); err != nil {
return diag.FromErr(err)
@@ -157,8 +161,12 @@ func typeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "TYPE", Name: typeName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewTypeBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewTypeBuilder(metaDb, o)
if v, ok := d.GetOk("row_properties"); ok {
p := materialize.GetRowProperties(v)
@@ -182,7 +190,7 @@ func typeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -193,7 +201,7 @@ func typeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -203,11 +211,11 @@ func typeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
}
// set id
- i, err := materialize.TypeId(meta.(*sqlx.DB), o)
+ i, err := materialize.TypeId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return typeRead(ctx, d, meta)
}
@@ -217,8 +225,12 @@ func typeUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "TYPE", Name: typeName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
@@ -230,7 +242,7 @@ func typeUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -245,8 +257,12 @@ func typeDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diag
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: typeName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewTypeBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewTypeBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_type_test.go b/pkg/resources/resource_type_test.go
index 57a5466b..36932e7b 100644
--- a/pkg/resources/resource_type_test.go
+++ b/pkg/resources/resource_type_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -24,7 +24,7 @@ func TestResourceTypeCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, Type().Schema, inType)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(`CREATE TYPE "database"."schema"."type" AS LIST \(ELEMENT TYPE = int4\);`).WillReturnResult(sqlmock.NewResult(1, 1))
@@ -51,7 +51,7 @@ func TestResourceTypeReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_types.id = 'u1'`
testhelpers.MockTypeScan(mock, pp)
@@ -72,7 +72,7 @@ func TestResourceTypeDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, Type().Schema, inType)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP TYPE "database"."schema"."type";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := typeDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/resource_user.go b/pkg/resources/resource_user.go
new file mode 100644
index 00000000..35e04d7e
--- /dev/null
+++ b/pkg/resources/resource_user.go
@@ -0,0 +1,300 @@
+package resources
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func User() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: userCreate,
+ ReadContext: userRead,
+ // UpdateContext: userUpdate,
+ DeleteContext: userDelete,
+
+ Importer: &schema.ResourceImporter{
+ StateContext: schema.ImportStatePassthroughContext,
+ },
+
+ Schema: map[string]*schema.Schema{
+ "email": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "The email address of the user. This must be unique across all users in the organization.",
+ },
+ "auth_provider": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The authentication provider for the user.",
+ },
+ "roles": {
+ Type: schema.TypeList,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Required: true,
+ ForceNew: true,
+ Description: "The roles to assign to the user. Allowed values are 'Member' and 'Admin'.",
+ },
+ "verified": {
+ Type: schema.TypeBool,
+ Computed: true,
+ },
+ "metadata": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ }
+}
+
+// CreateUserRequest is used to serialize the request body for creating a new user.
+type CreateUserRequest struct {
+ Email string `json:"email"`
+ RoleIDs []string `json:"roleIds"`
+}
+
+// CreatedUser represents the expected structure of a user creation response.
+type CreatedUser struct {
+ ID string `json:"id"`
+ Email string `json:"email"`
+ ProfilePictureURL string `json:"profilePictureUrl"`
+ Verified bool `json:"verified"`
+ Metadata string `json:"metadata"`
+ Provider string `json:"provider"`
+}
+
+type FronteggRolesResponse struct {
+ Items []FronteggRole `json:"items"`
+ Metadata struct {
+ TotalItems int `json:"totalItems"`
+ TotalPages int `json:"totalPages"`
+ } `json:"_metadata"`
+}
+
+type FronteggRole struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+}
+
+// userCreate is the Terraform resource create function for a Frontegg user.
+func userCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ providerMeta, err := utils.GetProviderMeta(meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ client := providerMeta.Frontegg
+ email := d.Get("email").(string)
+ roleNames := convertToStringSlice(d.Get("roles").([]interface{}))
+
+ for _, roleName := range roleNames {
+ if roleName != "Member" && roleName != "Admin" {
+ return diag.Errorf("invalid role: %s. Roles must be either 'Member' or 'Admin'", roleName)
+ }
+ }
+
+ // Fetch role IDs based on role names.
+ roleMap, err := listRoles(ctx, client)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error fetching roles: %s", err))
+ }
+
+ var roleIDs []string
+ for _, roleName := range roleNames {
+ if roleID, ok := roleMap[roleName]; ok {
+ roleIDs = append(roleIDs, roleID)
+ } else {
+ // Consider failing the process if the role is not found
+ return diag.Errorf("role not found: %s", roleName)
+ }
+ }
+
+ createUserRequest := CreateUserRequest{
+ Email: email,
+ RoleIDs: roleIDs,
+ }
+
+ requestBody, err := json.Marshal(createUserRequest)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error marshaling create user request: %s", err))
+ }
+
+ req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/identity/resources/users/v2", client.Endpoint), bytes.NewBuffer(requestBody))
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error creating request: %s", err))
+ }
+
+ req.Header.Add("Content-Type", "application/json")
+ req.Header.Add("Authorization", "Bearer "+client.Token)
+
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error sending request: %s", err))
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusCreated {
+ return diag.FromErr(fmt.Errorf("error creating user: status %d", resp.StatusCode))
+ }
+
+ var createdUser CreatedUser
+ if err := json.NewDecoder(resp.Body).Decode(&createdUser); err != nil {
+ return diag.FromErr(fmt.Errorf("error decoding response: %s", err))
+ }
+
+ d.Set("verified", createdUser.Verified)
+ d.Set("metadata", createdUser.Metadata)
+ d.Set("auth_provider", createdUser.Provider)
+ d.SetId(createdUser.ID)
+ return nil
+}
+
+func userRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ providerMeta, err := utils.GetProviderMeta(meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ client := providerMeta.Frontegg
+ userID := d.Id()
+
+ // Construct the API request
+ req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/identity/resources/users/v1/%s", client.Endpoint, userID), nil)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error creating request: %s", err))
+ }
+ req.Header.Add("Authorization", "Bearer "+client.Token)
+
+ // Send the request to the Frontegg API
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error reading user: %s", err))
+ }
+ defer resp.Body.Close()
+
+ // Check for a successful response
+ if resp.StatusCode != http.StatusOK {
+ // If the user is not found, remove it from the Terraform state
+ if resp.StatusCode == http.StatusNotFound {
+ d.SetId("")
+ return nil
+ }
+ return diag.Errorf("API error: %s", resp.Status)
+ }
+
+ // Parse the response body
+ var user CreatedUser
+ if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
+ return diag.FromErr(fmt.Errorf("error decoding user response: %s", err))
+ }
+
+ // Update the Terraform state with the fetched user data
+ d.Set("email", user.Email)
+ d.Set("verified", user.Verified)
+ d.Set("metadata", user.Metadata)
+ d.Set("auth_provider", user.Provider)
+
+ return nil
+}
+
+// TODO: Add userUpdate function to change user roles
+
+// userDelete is the Terraform resource delete function for a Frontegg user.
+func userDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ providerMeta, err := utils.GetProviderMeta(meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ client := providerMeta.Frontegg
+ userID := d.Id()
+
+ // Send the request to the Frontegg API to delete the user.
+ req, err := http.NewRequestWithContext(ctx, "DELETE", fmt.Sprintf("%s/identity/resources/users/v1/%s", client.Endpoint, userID), nil)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error creating request to delete user: %s", err))
+ }
+ req.Header.Add("Authorization", "Bearer "+client.Token)
+
+ // Perform the request
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("error sending request to delete user: %s", err))
+ }
+ defer resp.Body.Close()
+
+ // Check for a successful response
+ if resp.StatusCode != http.StatusOK {
+ return diag.FromErr(fmt.Errorf("error deleting user: status %d", resp.StatusCode))
+ }
+
+ // Remove the user from the Terraform state
+ d.SetId("")
+ return nil
+}
+
+// convertToStringSlice is a helper function to convert an interface slice to a string slice.
+func convertToStringSlice(input []interface{}) []string {
+ result := make([]string, len(input))
+ for i, v := range input {
+ result[i] = v.(string)
+ }
+ return result
+}
+
+// listRoles fetches roles from the Frontegg API and returns a map of role names to their IDs.
+func listRoles(ctx context.Context, client *clients.FronteggClient) (map[string]string, error) {
+ rolesURL := fmt.Sprintf("%s/identity/resources/roles/v2", client.Endpoint)
+
+ req, err := http.NewRequestWithContext(ctx, "GET", rolesURL, nil)
+ if err != nil {
+ return nil, fmt.Errorf("error creating request: %v", err)
+ }
+ req.Header.Add("Authorization", "Bearer "+client.Token)
+
+ resp, err := client.HTTPClient.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("error executing request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("error fetching roles, status code: %d", resp.StatusCode)
+ }
+
+ // Read and reset the response body
+ responseBody, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("error reading response body: %v", err)
+ }
+ resp.Body = io.NopCloser(bytes.NewBuffer(responseBody))
+
+ // Decode the JSON response
+ var rolesResponse FronteggRolesResponse
+ if err := json.NewDecoder(resp.Body).Decode(&rolesResponse); err != nil {
+ return nil, fmt.Errorf("error decoding response: %v", err)
+ }
+
+ // Create a map of role names to their IDs
+ roleMap := make(map[string]string)
+ for _, role := range rolesResponse.Items {
+ log.Printf("[DEBUG] Role found: %s - %s\n", role.Name, role.ID)
+ if role.Name == "Organization Admin" {
+ roleMap["Admin"] = role.ID
+ } else if role.Name == "Organization Member" {
+ roleMap["Member"] = role.ID
+ }
+ }
+
+ return roleMap, nil
+}
diff --git a/pkg/resources/resource_user_test.go b/pkg/resources/resource_user_test.go
new file mode 100644
index 00000000..325bed0f
--- /dev/null
+++ b/pkg/resources/resource_user_test.go
@@ -0,0 +1,65 @@
+package resources
+
+import (
+ "context"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/stretchr/testify/require"
+)
+
+func TestUserResourceRead(t *testing.T) {
+ r := require.New(t)
+
+ testhelpers.WithMockFronteggServer(t, func(serverURL string) {
+ client := &clients.FronteggClient{
+ Endpoint: serverURL,
+ HTTPClient: &http.Client{},
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ }
+
+ providerMeta := &utils.ProviderMeta{
+ Frontegg: client,
+ }
+
+ d := schema.TestResourceDataRaw(t, User().Schema, nil)
+ d.SetId("mock-user-id")
+
+ if err := userRead(context.TODO(), d, providerMeta); err != nil {
+ t.Fatal(err)
+ }
+
+ r.Equal("test@example.com", d.Get("email"))
+ })
+}
+
+func TestUserResourceDelete(t *testing.T) {
+ r := require.New(t)
+
+ testhelpers.WithMockFronteggServer(t, func(serverURL string) {
+ client := &clients.FronteggClient{
+ Endpoint: serverURL,
+ HTTPClient: &http.Client{},
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ }
+
+ providerMeta := &utils.ProviderMeta{
+ Frontegg: client,
+ }
+
+ d := schema.TestResourceDataRaw(t, User().Schema, nil)
+ d.SetId("mock-user-id")
+
+ if err := userDelete(context.TODO(), d, providerMeta); err != nil {
+ t.Fatal(err)
+ }
+
+ // Assert the user is removed from the state
+ r.Empty(d.Id())
+ })
+}
diff --git a/pkg/resources/resource_view.go b/pkg/resources/resource_view.go
index 30e442fb..8a091add 100644
--- a/pkg/resources/resource_view.go
+++ b/pkg/resources/resource_view.go
@@ -10,7 +10,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
)
var viewSchema = map[string]*schema.Schema{
@@ -26,6 +25,7 @@ var viewSchema = map[string]*schema.Schema{
ForceNew: true,
},
"ownership_role": OwnershipRoleSchema(),
+ "region": RegionSchema(),
}
func View() *schema.Resource {
@@ -48,7 +48,11 @@ func View() *schema.Resource {
func viewRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
i := d.Id()
- s, err := materialize.ScanView(meta.(*sqlx.DB), utils.ExtractId(i))
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ s, err := materialize.ScanView(metaDb, utils.ExtractId(i))
if err == sql.ErrNoRows {
d.SetId("")
return nil
@@ -56,7 +60,7 @@ func viewRead(ctx context.Context, d *schema.ResourceData, meta interface{}) dia
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
if err := d.Set("name", s.ViewName.String); err != nil {
return diag.FromErr(err)
@@ -91,8 +95,12 @@ func viewCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, region, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "VIEW", Name: viewName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewViewBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewViewBuilder(metaDb, o)
if v, ok := d.GetOk("statement"); ok && v.(string) != "" {
b.SelectStmt(v.(string))
@@ -105,7 +113,7 @@ func viewCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
// ownership
if v, ok := d.GetOk("ownership_role"); ok {
- ownership := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ ownership := materialize.NewOwnershipBuilder(metaDb, o)
if err := ownership.Alter(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed ownership, dropping object: %s", o.Name)
@@ -116,7 +124,7 @@ func viewCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
// object comment
if v, ok := d.GetOk("comment"); ok {
- comment := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ comment := materialize.NewCommentBuilder(metaDb, o)
if err := comment.Object(v.(string)); err != nil {
log.Printf("[DEBUG] resource failed comment, dropping object: %s", o.Name)
@@ -126,11 +134,11 @@ func viewCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
}
// set id
- i, err := materialize.ViewId(meta.(*sqlx.DB), o)
+ i, err := materialize.ViewId(metaDb, o)
if err != nil {
return diag.FromErr(err)
}
- d.SetId(utils.TransformIdWithRegion(i))
+ d.SetId(utils.TransformIdWithRegion(string(region), i))
return viewRead(ctx, d, meta)
}
@@ -140,12 +148,16 @@ func viewUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{ObjectType: "VIEW", Name: viewName, SchemaName: schemaName, DatabaseName: databaseName}
if d.HasChange("name") {
oldName, newViewName := d.GetChange("name")
o := materialize.MaterializeObject{ObjectType: "VIEW", Name: oldName.(string), SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewViewBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewViewBuilder(metaDb, o)
if err := b.Rename(newViewName.(string)); err != nil {
return diag.FromErr(err)
@@ -154,7 +166,7 @@ func viewUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
if d.HasChange("ownership_role") {
_, newRole := d.GetChange("ownership_role")
- b := materialize.NewOwnershipBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewOwnershipBuilder(metaDb, o)
if err := b.Alter(newRole.(string)); err != nil {
return diag.FromErr(err)
@@ -163,7 +175,7 @@ func viewUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) d
if d.HasChange("comment") {
_, newComment := d.GetChange("comment")
- b := materialize.NewCommentBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewCommentBuilder(metaDb, o)
if err := b.Object(newComment.(string)); err != nil {
return diag.FromErr(err)
@@ -178,8 +190,12 @@ func viewDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diag
schemaName := d.Get("schema_name").(string)
databaseName := d.Get("database_name").(string)
+ metaDb, _, err := utils.GetDBClientFromMeta(meta, d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
o := materialize.MaterializeObject{Name: viewName, SchemaName: schemaName, DatabaseName: databaseName}
- b := materialize.NewViewBuilder(meta.(*sqlx.DB), o)
+ b := materialize.NewViewBuilder(metaDb, o)
if err := b.Drop(); err != nil {
return diag.FromErr(err)
diff --git a/pkg/resources/resource_view_test.go b/pkg/resources/resource_view_test.go
index 06226206..7d641754 100644
--- a/pkg/resources/resource_view_test.go
+++ b/pkg/resources/resource_view_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
@@ -24,7 +24,7 @@ func TestResourceViewCreate(t *testing.T) {
d := schema.TestResourceDataRaw(t, View().Schema, inView)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Create
mock.ExpectExec(`CREATE VIEW "database"."schema"."view" AS SELECT 1 FROM 1;`).WillReturnResult(sqlmock.NewResult(1, 1))
@@ -51,7 +51,7 @@ func TestResourceViewReadIdMigration(t *testing.T) {
// Set id before migration
d.SetId("u1")
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
// Query Params
pp := `WHERE mz_views.id = 'u1'`
testhelpers.MockViewScan(mock, pp)
@@ -75,7 +75,7 @@ func TestResourceViewUpdate(t *testing.T) {
d.Set("name", "old_view")
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER VIEW "database"."schema"."" RENAME TO "view";`).WillReturnResult(sqlmock.NewResult(1, 1))
// Query Params
@@ -99,7 +99,7 @@ func TestResourceViewDelete(t *testing.T) {
d := schema.TestResourceDataRaw(t, View().Schema, in)
r.NotNil(d)
- testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ testhelpers.WithMockProviderMeta(t, func(db *utils.ProviderMeta, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP VIEW "database"."schema"."view";`).WillReturnResult(sqlmock.NewResult(1, 1))
if err := viewDelete(context.TODO(), d, db); err != nil {
diff --git a/pkg/resources/schema.go b/pkg/resources/schema.go
index 2e219445..34b6d46e 100644
--- a/pkg/resources/schema.go
+++ b/pkg/resources/schema.go
@@ -512,3 +512,12 @@ func CommentSchema(forceNew bool) *schema.Schema {
ForceNew: forceNew,
}
}
+
+func RegionSchema() *schema.Schema {
+ return &schema.Schema{
+ Description: "The region to use for the resource connection. If not set, the default region is used.",
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ }
+}
diff --git a/pkg/testhelpers/helpers.go b/pkg/testhelpers/helpers.go
index 885bd405..9a4c5ccb 100644
--- a/pkg/testhelpers/helpers.go
+++ b/pkg/testhelpers/helpers.go
@@ -1,17 +1,34 @@
package testhelpers
import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "strings"
"testing"
+ "time"
sqlmock "github.com/DATA-DOG/go-sqlmock"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
"github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
"github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
)
+type MockAppPassword struct {
+ ClientID string `json:"clientId"`
+ Description string `json:"description"`
+ Owner string `json:"owner"`
+ CreatedAt time.Time `json:"created_at"`
+ Secret string `json:"secret"`
+}
+
func WithMockDb(t *testing.T, f func(*sqlx.DB, sqlmock.Sqlmock)) {
// Set the region for testing
- utils.Region = "aws/us-east-1"
+ utils.DefaultRegion = "aws/us-east-1"
t.Helper()
r := require.New(t)
@@ -24,3 +41,186 @@ func WithMockDb(t *testing.T, f func(*sqlx.DB, sqlmock.Sqlmock)) {
f(dbx, mock)
}
+
+func WithMockProviderMeta(t *testing.T, f func(*utils.ProviderMeta, sqlmock.Sqlmock)) {
+ t.Helper()
+ r := require.New(t)
+ db, mock, err := sqlmock.New()
+ r.NoError(err)
+ defer db.Close()
+
+ dbx := sqlx.NewDb(db, "sqlmock")
+ dbClients := make(map[clients.Region]*clients.DBClient)
+ dbClients[clients.AwsUsEast1] = &clients.DBClient{DB: dbx}
+ regionsEnabled := make(map[clients.Region]bool)
+ regionsEnabled[clients.AwsUsEast1] = true
+
+ providerMeta := &utils.ProviderMeta{
+ DB: dbClients,
+ RegionsEnabled: regionsEnabled,
+ DefaultRegion: clients.AwsUsEast1,
+ Frontegg: &clients.FronteggClient{
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ },
+ CloudAPI: nil,
+ }
+
+ mock.MatchExpectationsInOrder(true)
+
+ f(providerMeta, mock)
+}
+
+func WithMockFronteggServer(t *testing.T, f func(url string)) {
+ t.Helper()
+ r := require.New(t)
+
+ // Create a mock HTTP server
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ switch req.URL.Path {
+ case "/identity/resources/users/api-tokens/v1":
+ switch req.Method {
+ case http.MethodPost:
+ var createReq struct {
+ Description string `json:"description"`
+ }
+ err := json.NewDecoder(req.Body).Decode(&createReq)
+ r.NoError(err)
+
+ appPassword := MockAppPassword{
+ ClientID: "mock-client-id",
+ Description: createReq.Description,
+ Owner: "mockOwner",
+ CreatedAt: time.Now(),
+ Secret: "mock-secret",
+ }
+
+ w.WriteHeader(http.StatusCreated)
+ json.NewEncoder(w).Encode(appPassword)
+ case http.MethodGet:
+ mockAppPassword := MockAppPassword{
+ ClientID: "mock-client-id",
+ Description: "test-app-password",
+ Owner: "mockOwner",
+ CreatedAt: time.Now(),
+ Secret: "mock-secret",
+ }
+ json.NewEncoder(w).Encode([]MockAppPassword{mockAppPassword})
+ case http.MethodDelete:
+ w.WriteHeader(http.StatusNoContent)
+ default:
+ http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
+ }
+ case "/identity/resources/users/v1/mock-user-id":
+ switch req.Method {
+ case http.MethodGet:
+ if strings.HasSuffix(req.URL.Path, "/mock-user-id") {
+ mockUser := struct {
+ ID string `json:"id"`
+ Email string `json:"email"`
+ ProfilePictureURL string `json:"profilePictureUrl"`
+ Verified bool `json:"verified"`
+ Metadata string `json:"metadata"`
+ }{
+ ID: "mock-user-id",
+ Email: "test@example.com",
+ ProfilePictureURL: "http://example.com/picture.jpg",
+ Verified: true,
+ Metadata: "{}",
+ }
+ json.NewEncoder(w).Encode(mockUser)
+ } else {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ case http.MethodDelete:
+ if strings.HasSuffix(req.URL.Path, "/mock-user-id") {
+ w.WriteHeader(http.StatusOK)
+ } else {
+ w.WriteHeader(http.StatusNotFound)
+ }
+ }
+
+ default:
+ http.Error(w, "Not Found", http.StatusNotFound)
+ }
+ }))
+ defer server.Close()
+
+ f(server.URL)
+}
+
+// MockCloudService is a mock implementation of the http.RoundTripper interface for cloud-related requests
+type MockCloudService struct{}
+
+func (m *MockCloudService) RoundTrip(req *http.Request) (*http.Response, error) {
+ // Check the requested URL and return a response accordingly
+ if strings.HasSuffix(req.URL.Path, "/api/cloud-regions") {
+ // Mock response data
+ data := clients.CloudProviderResponse{
+ Data: []clients.CloudProvider{
+ {ID: "aws/us-east-1", Name: "us-east-1", Url: "http://mockendpoint", CloudProvider: "aws"},
+ {ID: "aws/eu-west-1", Name: "eu-west-1", Url: "http://mockendpoint", CloudProvider: "aws"},
+ },
+ }
+
+ // Convert response data to JSON
+ respData, _ := json.Marshal(data)
+
+ // Create a new HTTP response with the JSON data
+ return &http.Response{
+ StatusCode: http.StatusOK,
+ Body: io.NopCloser(bytes.NewReader(respData)),
+ Header: make(http.Header),
+ }, nil
+ } else if strings.HasSuffix(req.URL.Path, "/api/region") {
+ // Return mock response for GetRegionDetails
+ details := clients.CloudRegion{
+ RegionInfo: &clients.RegionInfo{
+ SqlAddress: "sql.materialize.com",
+ HttpAddress: "http.materialize.com",
+ Resolvable: true,
+ EnabledAt: "2021-01-01T00:00:00Z",
+ },
+ }
+ respData, _ := json.Marshal(details)
+ return &http.Response{
+ StatusCode: http.StatusOK,
+ Body: io.NopCloser(bytes.NewReader(respData)),
+ Header: make(http.Header),
+ }, nil
+ }
+ return nil, fmt.Errorf("no mock available for the requested endpoint")
+}
+
+// WithMockCloudServer sets up a mock HTTP server for cloud-related requests and calls the provided function with the server URL.
+func WithMockCloudServer(t *testing.T, f func(url string)) {
+ t.Helper()
+
+ // Create a mock HTTP server
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ // Use the MockCloudService for handling requests
+ m := &MockCloudService{}
+ resp, err := m.RoundTrip(req)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // Copy the response to the server's response writer
+ copyHeaders(w.Header(), resp.Header)
+ w.WriteHeader(resp.StatusCode)
+ _, _ = io.Copy(w, resp.Body)
+ }))
+
+ defer server.Close()
+
+ f(server.URL)
+}
+
+// Helper function to copy headers from the response to the writer
+func copyHeaders(dst, src http.Header) {
+ for key, values := range src {
+ for _, value := range values {
+ dst.Add(key, value)
+ }
+ }
+}
diff --git a/pkg/testhelpers/helpers_test.go b/pkg/testhelpers/helpers_test.go
new file mode 100644
index 00000000..d0113e64
--- /dev/null
+++ b/pkg/testhelpers/helpers_test.go
@@ -0,0 +1,129 @@
+package testhelpers
+
+import (
+ "encoding/json"
+ "net/http"
+ "strings"
+ "testing"
+
+ sqlmock "github.com/DATA-DOG/go-sqlmock"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/utils"
+ "github.com/jmoiron/sqlx"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestWithMockDb(t *testing.T) {
+ WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
+ rows := sqlmock.NewRows([]string{"number"}).AddRow(1)
+ mock.ExpectQuery("^SELECT 1$").WillReturnRows(rows)
+ var result int
+ err := db.Get(&result, "SELECT 1")
+ assert.NoError(t, err)
+ assert.Equal(t, 1, result)
+ err = mock.ExpectationsWereMet()
+ assert.NoError(t, err)
+ })
+}
+
+func TestWithMockProviderMeta(t *testing.T) {
+ WithMockProviderMeta(t, func(providerMeta *utils.ProviderMeta, mock sqlmock.Sqlmock) {
+ // Assert that the providerMeta is not nil
+ assert.NotNil(t, providerMeta)
+
+ // Assert that the providerMeta has the expected default region
+ assert.Equal(t, clients.AwsUsEast1, providerMeta.DefaultRegion)
+
+ // Assert that the providerMeta has the expected regions enabled
+ assert.True(t, providerMeta.RegionsEnabled[clients.AwsUsEast1])
+
+ // Optionally, set up mock expectations if you are going to perform any database operations
+ mock.ExpectQuery("SELECT VERSION()").WillReturnRows(sqlmock.NewRows([]string{"version"}).AddRow("test-version"))
+
+ // Perform a database operation using providerMeta.DB[clients.AwsUsEast1]
+ var version string
+ err := providerMeta.DB[clients.AwsUsEast1].DB.Get(&version, "SELECT VERSION()")
+ require.NoError(t, err)
+ assert.Equal(t, "test-version", version)
+
+ err = mock.ExpectationsWereMet()
+ assert.NoError(t, err)
+ })
+}
+
+func TestWithMockFronteggServer(t *testing.T) {
+ t.Run("TestWithMockFronteggServer_PostRequest", func(t *testing.T) {
+ WithMockFronteggServer(t, func(url string) {
+ // Perform HTTP POST request to the mock server and assert the response
+ req, err := http.NewRequest(http.MethodPost, url+"/identity/resources/users/api-tokens/v1", strings.NewReader(`{"description":"test-description"}`))
+ require.NoError(t, err)
+
+ resp, err := http.DefaultClient.Do(req)
+ require.NoError(t, err)
+ defer resp.Body.Close()
+
+ assert.Equal(t, http.StatusCreated, resp.StatusCode)
+
+ var appPassword MockAppPassword
+ err = json.NewDecoder(resp.Body).Decode(&appPassword)
+ require.NoError(t, err)
+
+ assert.Equal(t, "mock-client-id", appPassword.ClientID)
+ assert.Equal(t, "test-description", appPassword.Description)
+ assert.Equal(t, "mockOwner", appPassword.Owner)
+ assert.NotNil(t, appPassword.CreatedAt)
+ assert.Equal(t, "mock-secret", appPassword.Secret)
+ })
+ })
+
+ t.Run("TestWithMockFronteggServer_GetRequest", func(t *testing.T) {
+ WithMockFronteggServer(t, func(url string) {
+ resp, err := http.Get(url + "/identity/resources/users/api-tokens/v1")
+ require.NoError(t, err)
+ defer resp.Body.Close()
+
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
+
+ var appPasswords []MockAppPassword
+ err = json.NewDecoder(resp.Body).Decode(&appPasswords)
+ require.NoError(t, err)
+
+ require.Len(t, appPasswords, 1)
+ appPassword := appPasswords[0]
+ assert.Equal(t, "mock-client-id", appPassword.ClientID)
+ assert.Equal(t, "test-app-password", appPassword.Description)
+ assert.Equal(t, "mockOwner", appPassword.Owner)
+ assert.NotNil(t, appPassword.CreatedAt)
+ assert.Equal(t, "mock-secret", appPassword.Secret)
+ })
+ })
+}
+
+func TestMockCloudService_RoundTrip(t *testing.T) {
+ t.Run("TestMockCloudService_RoundTrip_ValidURL", func(t *testing.T) {
+ mockService := &MockCloudService{}
+ req, err := http.NewRequest(http.MethodGet, "http://example.com/api/cloud-regions", nil)
+ assert.NoError(t, err)
+
+ resp, err := mockService.RoundTrip(req)
+ assert.NoError(t, err)
+ defer resp.Body.Close()
+
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
+ })
+}
+
+func TestCopyHeaders(t *testing.T) {
+ t.Run("TestCopyHeaders", func(t *testing.T) {
+ dstHeader := make(http.Header)
+ srcHeader := http.Header{
+ "Content-Type": []string{"application/json"},
+ "Authorization": []string{"Bearer token"},
+ }
+
+ copyHeaders(dstHeader, srcHeader)
+ assert.Equal(t, "application/json", dstHeader.Get("Content-Type"))
+ assert.Equal(t, "Bearer token", dstHeader.Get("Authorization"))
+ })
+}
diff --git a/pkg/utils/ids_migration_helper.go b/pkg/utils/ids_migration_helper.go
deleted file mode 100644
index 50f77abb..00000000
--- a/pkg/utils/ids_migration_helper.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package utils
-
-import (
- "context"
- "fmt"
- "strings"
-)
-
-var Region string
-
-func SetRegionFromHostname(host string) error {
- defaultRegion := "aws/us-east-1"
- if host == "localhost" || host == "materialize" || host == "materialized" || host == "127.0.0.1" {
- Region = defaultRegion
- return nil
- }
-
- parts := strings.Split(host, ".")
- if len(parts) < 3 {
- Region = defaultRegion
- return nil
- }
-
- Region = fmt.Sprintf("aws/%s", parts[1])
- return nil
-}
-
-// Helper function to prepend region to the ID
-func TransformIdWithRegion(oldID string) string {
- // If the ID already has a region, return the original ID
- if strings.Contains(oldID, ":") {
- return oldID
- }
- return fmt.Sprintf("%s:%s", Region, oldID)
-}
-
-// Function to get the ID from the region + ID string
-func ExtractId(oldID string) string {
- parts := strings.Split(oldID, ":")
- if len(parts) < 2 {
- // Return the original ID if it doesn't have a region
- return oldID
- }
- return parts[1]
-}
-
-func IdStateUpgradeV0(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
- oldID, ok := rawState["id"].(string)
- if !ok {
- return nil, fmt.Errorf("unexpected type for ID")
- }
-
- newID := TransformIdWithRegion(oldID)
- rawState["id"] = newID
-
- return rawState, nil
-}
diff --git a/pkg/utils/ids_migration_helper_test.go b/pkg/utils/ids_migration_helper_test.go
deleted file mode 100644
index bffced87..00000000
--- a/pkg/utils/ids_migration_helper_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package utils
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestTransformIdWithRegion(t *testing.T) {
- SetRegionFromHostname("localhost")
- testCases := []map[string]interface{}{
- {
- "input": "aws/us-east-1:GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
- "expected": "aws/us-east-1:GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
- },
- {
- "input": "GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
- "expected": "aws/us-east-1:GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
- },
- {
- "input": "aws/us-east-1:u1",
- "expected": "aws/us-east-1:u1",
- },
- {
- "input": "u1",
- "expected": "aws/us-east-1:u1",
- },
- }
- for tc := range testCases {
- c := testCases[tc]
- o := TransformIdWithRegion(c["input"].(string))
- assert.Equal(t, o, c["expected"].(string))
- }
-}
diff --git a/pkg/utils/provider_meta.go b/pkg/utils/provider_meta.go
new file mode 100644
index 00000000..32674877
--- /dev/null
+++ b/pkg/utils/provider_meta.go
@@ -0,0 +1,107 @@
+package utils
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/jmoiron/sqlx"
+)
+
+// ProviderMeta holds essential configuration and client information
+// required across various parts of the provider. It acts as a central
+// repository of shared data, particularly for database connections, API clients,
+// and regional settings.
+type ProviderMeta struct {
+ // DB is a map that associates each supported region with its corresponding
+ // database client. This allows for region-specific database operations.
+ DB map[clients.Region]*clients.DBClient
+
+ // Frontegg represents the client used to interact with the Frontegg API,
+ // which may involve authentication, token management, etc.
+ Frontegg *clients.FronteggClient
+
+ // CloudAPI is the client used for interactions with the cloud API
+ CloudAPI *clients.CloudAPIClient
+
+ // DefaultRegion specifies the default region to be used when no specific
+ // region is provided in the resources and data sources.
+ DefaultRegion clients.Region
+
+ // RegionsEnabled is a map indicating which regions are currently enabled
+ // for use. This can be used to quickly check the availability in different regions.
+ RegionsEnabled map[clients.Region]bool
+}
+
+var DefaultRegion string
+
+func GetProviderMeta(meta interface{}) (*ProviderMeta, error) {
+ providerMeta := meta.(*ProviderMeta)
+
+ if err := providerMeta.Frontegg.NeedsTokenRefresh(); err != nil {
+ err := providerMeta.Frontegg.RefreshToken()
+ if err != nil {
+ return nil, fmt.Errorf("failed to refresh token: %v", err)
+ }
+ }
+
+ return providerMeta, nil
+}
+
+func GetDBClientFromMeta(meta interface{}, d *schema.ResourceData) (*sqlx.DB, clients.Region, error) {
+ providerMeta, err := GetProviderMeta(meta)
+ if err != nil {
+ return nil, "", err
+ }
+
+ // Determine the region to use, if one is not specified, use the default region
+ var region clients.Region
+ if d != nil && d.Get("region") != "" {
+ region = clients.Region(d.Get("region").(string))
+ } else {
+ region = providerMeta.DefaultRegion
+ }
+
+ // Check if the region is enabled using the stored information
+ enabled, exists := providerMeta.RegionsEnabled[region]
+ if !exists {
+ return nil, region, fmt.Errorf("no information available for region: %s", region)
+ }
+
+ if !enabled {
+ return nil, region, fmt.Errorf("region '%s' is not enabled", region)
+ }
+
+ // Retrieve the appropriate DBClient for the region from the map
+ dbClient, exists := providerMeta.DB[region]
+ if !exists {
+ return nil, region, fmt.Errorf("no database client for region: %s", region)
+ }
+
+ return dbClient.SQLX(), region, nil
+}
+
+func SetDefaultRegion(region string) error {
+ DefaultRegion = region
+ return nil
+}
+
+// Helper function to prepend region to the ID
+func TransformIdWithRegion(region string, oldID string) string {
+ // If the ID already has a region, return the original ID
+ if strings.Contains(oldID, ":") {
+ return oldID
+ }
+ return fmt.Sprintf("%s:%s", region, oldID)
+}
+
+// Function to get the ID from the region + ID string
+func ExtractId(oldID string) string {
+ parts := strings.Split(oldID, ":")
+ if len(parts) < 2 {
+ // Return the original ID if it doesn't have a region
+ return oldID
+ }
+ return parts[1]
+}
diff --git a/pkg/utils/provider_meta_test.go b/pkg/utils/provider_meta_test.go
new file mode 100644
index 00000000..0ead0c83
--- /dev/null
+++ b/pkg/utils/provider_meta_test.go
@@ -0,0 +1,85 @@
+package utils
+
+import (
+ "testing"
+ "time"
+
+ "github.com/DATA-DOG/go-sqlmock"
+ "github.com/MaterializeInc/terraform-provider-materialize/pkg/clients"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/jmoiron/sqlx"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestGetDBClientFromMeta(t *testing.T) {
+ // Set up the SQL mock database
+ db, mock, err := sqlmock.New()
+ require.NoError(t, err)
+ defer db.Close()
+
+ // Wrap the sql.DB with sqlx
+ dbx := sqlx.NewDb(db, "sqlmock")
+
+ // Set up the mock ProviderMeta
+ providerMeta := &ProviderMeta{
+ DB: map[clients.Region]*clients.DBClient{
+ clients.AwsUsEast1: {DB: dbx},
+ },
+ RegionsEnabled: map[clients.Region]bool{
+ clients.AwsUsEast1: true,
+ },
+ DefaultRegion: clients.AwsUsEast1,
+ Frontegg: &clients.FronteggClient{
+ TokenExpiry: time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
+ },
+ }
+
+ // Create a ResourceData schema with the "region" key
+ resourceDataSchema := map[string]*schema.Schema{
+ "region": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ }
+
+ // Create a ResourceData object with a valid region
+ resourceData := schema.TestResourceDataRaw(t, resourceDataSchema, nil)
+ err = resourceData.Set("region", "aws/us-east-1")
+ require.NoError(t, err)
+
+ // Call the GetDBClientFromMeta function
+ dbClient, _, err := GetDBClientFromMeta(providerMeta, resourceData)
+ require.NoError(t, err)
+ assert.NotNil(t, dbClient)
+
+ // Check that the mock expectations are met
+ err = mock.ExpectationsWereMet()
+ assert.NoError(t, err)
+}
+
+func TestTransformIdWithRegion(t *testing.T) {
+ testCases := []map[string]interface{}{
+ {
+ "input": "aws/us-east-1:GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
+ "expected": "aws/us-east-1:GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
+ },
+ {
+ "input": "GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
+ "expected": "aws/us-east-1:GRANT DEFAULT|SCHEMA|u1|u1|||USAGE",
+ },
+ {
+ "input": "aws/us-east-1:u1",
+ "expected": "aws/us-east-1:u1",
+ },
+ {
+ "input": "u1",
+ "expected": "aws/us-east-1:u1",
+ },
+ }
+ for tc, _ := range testCases {
+ c := testCases[tc]
+ o := TransformIdWithRegion("aws/us-east-1", c["input"].(string))
+ assert.Equal(t, o, c["expected"].(string))
+ }
+}
diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl
index a84bbbc6..9b986033 100644
--- a/templates/index.md.tmpl
+++ b/templates/index.md.tmpl
@@ -15,11 +15,9 @@ Configure the provider by adding the following block to your Terraform project:
## Schema
-* `host` (String) Materialize host. Can also come from the `MZ_HOST` environment variable.
-* `user` (String) Materialize user. Can also come from the `MZ_USER` environment variable.
-* `password` (String, Sensitive) Materialize host. Can also come from the `MZ_PASSWORD` environment variable.
-* `port` (Number) The Materialize port number to connect to at the server host. Can also come from the `MZ_PORT` environment variable. Defaults to 6875.
-* `database` (String) The Materialize database. Can also come from the `MZ_DATABASE` environment variable. Defaults to `materialize`.
+* `password` (String, Sensitive) Materialize App Password. Can also come from the `MZ_PASSWORD` environment variable.
+* `database` (String, Optional) The Materialize database. Can also come from the `MZ_DATABASE` environment variable. Defaults to `materialize`.
+* `default_region` (String, Optional) The Materialize AWS region. Can also come from the `MZ_DEFAULT_REGION` environment variable. Defaults to `aws/us-east-1`.
## Order precedence