Skip to content

Commit f052a39

Browse files
Create postgres redshift credential resource (#131)
1 parent 9d3796a commit f052a39

8 files changed

+717
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "dbt_cloud_postgres_credential Data Source - terraform-provider-dbt-cloud"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# dbt_cloud_postgres_credential (Data Source)
10+
11+
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Required
19+
20+
- `credential_id` (Number) Credential ID
21+
- `project_id` (Number) Project ID
22+
23+
### Read-Only
24+
25+
- `default_schema` (String) Default schema name
26+
- `id` (String) The ID of this resource.
27+
- `is_active` (Boolean) Whether the Postgres credential is active
28+
- `num_threads` (Number) Number of threads to use
29+
- `username` (String) Username for Postgres
30+
31+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "dbt_cloud_postgres_credential Resource - terraform-provider-dbt-cloud"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# dbt_cloud_postgres_credential (Resource)
10+
11+
12+
13+
14+
## Example Usage
15+
16+
```tf
17+
resource "dbt_cloud_postgres_credential" "test_credential" {
18+
is_active = true
19+
project_id = dbt_cloud_project.test_project.id
20+
type = "postgres"
21+
default_schema = "%s"
22+
username = "%s"
23+
password = "%s"
24+
num_threads = 3
25+
}
26+
```
27+
28+
29+
<!-- schema generated by tfplugindocs -->
30+
## Schema
31+
32+
### Required
33+
34+
- `default_schema` (String) Default schema name
35+
- `project_id` (Number) Project ID to create the Postgres/Redshift/AlloyDB credential in
36+
- `type` (String) Type of connection. One of (postgres/redshift) use postgres for alloydb connections
37+
- `username` (String) Username for Postgres/Redshift/AlloyDB
38+
39+
### Optional
40+
41+
- `is_active` (Boolean) Whether the Postgres/Redshift/AlloyDB credential is active
42+
- `num_threads` (Number) Number of threads to use
43+
- `password` (String, Sensitive) Password for Postgres/Redshift/AlloyDB
44+
- `target_name` (String) Default schema name
45+
46+
### Read-Only
47+
48+
- `credential_id` (Number) The system Postgres/Redshift/AlloyDB credential ID
49+
- `id` (String) The ID of this resource.
50+
51+
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package data_sources
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/gthesheep/terraform-provider-dbt-cloud/pkg/dbt_cloud"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
)
11+
12+
var postgresCredentialSchema = map[string]*schema.Schema{
13+
"project_id": &schema.Schema{
14+
Type: schema.TypeInt,
15+
Required: true,
16+
Description: "Project ID",
17+
},
18+
"credential_id": &schema.Schema{
19+
Type: schema.TypeInt,
20+
Required: true,
21+
Description: "Credential ID",
22+
},
23+
"is_active": &schema.Schema{
24+
Type: schema.TypeBool,
25+
Computed: true,
26+
Description: "Whether the Postgres credential is active",
27+
},
28+
"default_schema": &schema.Schema{
29+
Type: schema.TypeString,
30+
Computed: true,
31+
Description: "Default schema name",
32+
},
33+
"username": &schema.Schema{
34+
Type: schema.TypeString,
35+
Computed: true,
36+
Description: "Username for Postgres",
37+
},
38+
"num_threads": &schema.Schema{
39+
Type: schema.TypeInt,
40+
Computed: true,
41+
Description: "Number of threads to use",
42+
},
43+
}
44+
45+
func DatasourcePostgresCredential() *schema.Resource {
46+
return &schema.Resource{
47+
ReadContext: postgresCredentialRead,
48+
Schema: postgresCredentialSchema,
49+
}
50+
}
51+
52+
func postgresCredentialRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
53+
c := m.(*dbt_cloud.Client)
54+
55+
var diags diag.Diagnostics
56+
57+
credentialID := d.Get("credential_id").(int)
58+
projectID := d.Get("project_id").(int)
59+
60+
postgresCredential, err := c.GetPostgresCredential(projectID, credentialID)
61+
if err != nil {
62+
return diag.FromErr(err)
63+
}
64+
65+
if err := d.Set("is_active", postgresCredential.State == dbt_cloud.STATE_ACTIVE); err != nil {
66+
return diag.FromErr(err)
67+
}
68+
if err := d.Set("project_id", postgresCredential.Project_Id); err != nil {
69+
return diag.FromErr(err)
70+
}
71+
if err := d.Set("default_schema", postgresCredential.Default_Schema); err != nil {
72+
return diag.FromErr(err)
73+
}
74+
if err := d.Set("username", postgresCredential.Username); err != nil {
75+
return diag.FromErr(err)
76+
}
77+
if err := d.Set("num_threads", postgresCredential.Threads); err != nil {
78+
return diag.FromErr(err)
79+
}
80+
81+
d.SetId(fmt.Sprintf("%d%s%d", postgresCredential.Project_Id, dbt_cloud.ID_DELIMITER, *postgresCredential.ID))
82+
83+
return diags
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package data_sources_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
)
10+
11+
func TestAccDbtCloudPostgresCredentialDataSource(t *testing.T) {
12+
13+
randomProjectName := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
14+
15+
config := postgres_credential(randomProjectName, "moo", "baa", "maa", 64)
16+
17+
check := resource.ComposeAggregateTestCheckFunc(
18+
resource.TestCheckResourceAttrSet("data.dbt_cloud_postgres_credential.test", "credential_id"),
19+
resource.TestCheckResourceAttrSet("data.dbt_cloud_postgres_credential.test", "project_id"),
20+
resource.TestCheckResourceAttrSet("data.dbt_cloud_postgres_credential.test", "default_schema"),
21+
resource.TestCheckResourceAttrSet("data.dbt_cloud_postgres_credential.test", "username"),
22+
resource.TestCheckResourceAttrSet("data.dbt_cloud_postgres_credential.test", "num_threads"),
23+
)
24+
25+
resource.ParallelTest(t, resource.TestCase{
26+
Providers: providers(),
27+
Steps: []resource.TestStep{
28+
{
29+
Config: config,
30+
Check: check,
31+
},
32+
},
33+
})
34+
}
35+
36+
func postgres_credential(projectName string, defaultSchema string, username string, password string, numThreads int) string {
37+
return fmt.Sprintf(`
38+
resource "dbt_cloud_project" "test_credential_project" {
39+
name = "%s"
40+
}
41+
42+
resource "dbt_cloud_postgres_credential" "test_cred" {
43+
project_id = dbt_cloud_project.test_credential_project.id
44+
num_threads = 64
45+
type = "postgres"
46+
username = "baa"
47+
password = "maa"
48+
default_schema = "moo"
49+
}
50+
51+
data "dbt_cloud_postgres_credential" "test" {
52+
project_id = dbt_cloud_project.test_credential_project.id
53+
credential_id = dbt_cloud_postgres_credential.test_cred.credential_id
54+
}
55+
`, projectName)
56+
}

pkg/dbt_cloud/postgres_credential.go

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package dbt_cloud
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"strings"
8+
)
9+
10+
type PostgresCredential struct {
11+
ID *int `json:"id"`
12+
Account_Id int `json:"account_id"`
13+
Project_Id int `json:"project_id"`
14+
Type string `json:"type"`
15+
State int `json:"state"`
16+
Threads int `json:"threads"`
17+
Username string `json:"username"`
18+
Default_Schema string `json:"default_schema"`
19+
Target_Name string `json:"target_name"`
20+
Password string `json:"password,omitempty"`
21+
}
22+
23+
type PostgresCredentialListResponse struct {
24+
Data []PostgresCredential `json:"data"`
25+
Status ResponseStatus `json:"status"`
26+
}
27+
28+
type PostgresCredentialResponse struct {
29+
Data PostgresCredential `json:"data"`
30+
Status ResponseStatus `json:"status"`
31+
}
32+
33+
// GetPostgresCredential retrieves a specific Postgres credential by its ID
34+
func (c *Client) GetPostgresCredential(projectId int, credentialId int) (*PostgresCredential, error) {
35+
req, err := http.NewRequest("GET", fmt.Sprintf("%s/v3/accounts/%d/projects/%d/credentials/", c.HostURL, c.AccountID, projectId), nil)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
body, err := c.doRequest(req)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
PostgresCredentialListResponse := PostgresCredentialListResponse{}
46+
err = json.Unmarshal(body, &PostgresCredentialListResponse)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
for i, credential := range PostgresCredentialListResponse.Data {
52+
if *credential.ID == credentialId {
53+
return &PostgresCredentialListResponse.Data[i], nil
54+
}
55+
}
56+
57+
return nil, fmt.Errorf("did not find credential ID %d in project ID %d", credentialId, projectId)
58+
}
59+
60+
// CreatePostgresCredential creates a new Postgres credential
61+
func (c *Client) CreatePostgresCredential(projectId int, isActive bool, type_ string, defaultSchema string, targetName string, username string, password string, numThreads int) (*PostgresCredential, error) {
62+
newPostgresCredential := PostgresCredential{
63+
Account_Id: c.AccountID,
64+
Project_Id: projectId,
65+
Type: type_,
66+
State: STATE_ACTIVE, // TODO: make variable
67+
Threads: numThreads,
68+
Username: username,
69+
Default_Schema: defaultSchema,
70+
Target_Name: targetName,
71+
Password: password,
72+
}
73+
newPostgresCredentialData, err := json.Marshal(newPostgresCredential)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
req, err := http.NewRequest("POST", fmt.Sprintf("%s/v3/accounts/%d/projects/%d/credentials/", c.HostURL, c.AccountID, projectId), strings.NewReader(string(newPostgresCredentialData)))
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
body, err := c.doRequest(req)
84+
if err != nil {
85+
return nil, err
86+
}
87+
88+
postgresCredentialResponse := PostgresCredentialResponse{}
89+
err = json.Unmarshal(body, &postgresCredentialResponse)
90+
if err != nil {
91+
return nil, err
92+
}
93+
94+
return &postgresCredentialResponse.Data, nil
95+
}
96+
97+
// UpdatePostgresCredential updates an existing Postgres credential
98+
func (c *Client) UpdatePostgresCredential(projectId int, credentialId int, postgresCredential PostgresCredential) (*PostgresCredential, error) {
99+
postgresCredentialData, err := json.Marshal(postgresCredential)
100+
if err != nil {
101+
return nil, err
102+
}
103+
104+
req, err := http.NewRequest("POST", fmt.Sprintf("%s/v3/accounts/%d/projects/%d/credentials/%d/", c.HostURL, c.AccountID, projectId, credentialId), strings.NewReader(string(postgresCredentialData)))
105+
if err != nil {
106+
return nil, err
107+
}
108+
109+
body, err := c.doRequest(req)
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
postgresCredentialResponse := PostgresCredentialResponse{}
115+
err = json.Unmarshal(body, &postgresCredentialResponse)
116+
if err != nil {
117+
return nil, err
118+
}
119+
120+
return &postgresCredentialResponse.Data, nil
121+
}
122+
123+
// DeletePostgresCredential deletes a Postgres credential by its ID
124+
func (c *Client) DeletePostgresCredential(credentialId, projectId string) (string, error) {
125+
req, err := http.NewRequest("DELETE", fmt.Sprintf("%s/v3/accounts/%d/projects/%s/credentials/%s/", c.HostURL, c.AccountID, projectId, credentialId), nil)
126+
if err != nil {
127+
return "", err
128+
}
129+
130+
_, err = c.doRequest(req)
131+
if err != nil {
132+
return "", err
133+
}
134+
135+
return "", err
136+
}

pkg/provider/provider.go

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func Provider() *schema.Provider {
4141
"dbt_cloud_environment_variable": data_sources.DatasourceEnvironmentVariable(),
4242
"dbt_cloud_snowflake_credential": data_sources.DatasourceSnowflakeCredential(),
4343
"dbt_cloud_bigquery_credential": data_sources.DatasourceBigQueryCredential(),
44+
"dbt_cloud_postgres_credential": data_sources.DatasourcePostgresCredential(),
4445
"dbt_cloud_connection": data_sources.DatasourceConnection(),
4546
"dbt_cloud_bigquery_connection": data_sources.DatasourceBigQueryConnection(),
4647
"dbt_cloud_repository": data_sources.DatasourceRepository(),
@@ -57,6 +58,7 @@ func Provider() *schema.Provider {
5758
"dbt_cloud_databricks_credential": resources.ResourceDatabricksCredential(),
5859
"dbt_cloud_snowflake_credential": resources.ResourceSnowflakeCredential(),
5960
"dbt_cloud_bigquery_credential": resources.ResourceBigQueryCredential(),
61+
"dbt_cloud_postgres_credential": resources.ResourcePostgresCredential(),
6062
"dbt_cloud_connection": resources.ResourceConnection(),
6163
"dbt_cloud_bigquery_connection": resources.ResourceBigQueryConnection(),
6264
"dbt_cloud_repository": resources.ResourceRepository(),

0 commit comments

Comments
 (0)