Skip to content

Commit 31bafd6

Browse files
committed
Add generic database and postgresql user provider
1 parent beeed78 commit 31bafd6

13 files changed

+1038
-111
lines changed
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package ovh
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net/url"
7+
"sort"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
"github.com/ovh/terraform-provider-ovh/ovh/helpers"
11+
"github.com/ovh/terraform-provider-ovh/ovh/helpers/hashcode"
12+
)
13+
14+
func dataSourceCloudProjectDatabaseUsers() *schema.Resource {
15+
return &schema.Resource{
16+
Read: dataSourceCloudProjectDatabaseUsersRead,
17+
Schema: map[string]*schema.Schema{
18+
"service_name": {
19+
Type: schema.TypeString,
20+
Required: true,
21+
DefaultFunc: schema.EnvDefaultFunc("OVH_CLOUD_PROJECT_SERVICE", nil),
22+
},
23+
"engine": {
24+
Type: schema.TypeString,
25+
Description: "Name of the engine of the service",
26+
Required: true,
27+
},
28+
"cluster_id": {
29+
Type: schema.TypeString,
30+
Description: "Cluster ID",
31+
Required: true,
32+
},
33+
34+
//Computed
35+
"result": {
36+
Type: schema.TypeList,
37+
Description: "List of users ids",
38+
Computed: true,
39+
Elem: &schema.Schema{Type: schema.TypeString},
40+
},
41+
},
42+
}
43+
}
44+
45+
func dataSourceCloudProjectDatabaseUsersRead(d *schema.ResourceData, meta interface{}) error {
46+
config := meta.(*Config)
47+
serviceName := d.Get("service_name").(string)
48+
engine := d.Get("engine").(string)
49+
clusterId := d.Get("cluster_id").(string)
50+
51+
endpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s/user",
52+
url.PathEscape(serviceName),
53+
url.PathEscape(engine),
54+
url.PathEscape(clusterId),
55+
)
56+
57+
res := make([]string, 0)
58+
59+
log.Printf("[DEBUG] Will read users from cluster %s from project %s", clusterId, serviceName)
60+
if err := config.OVHClient.Get(endpoint, &res); err != nil {
61+
return helpers.CheckDeleted(d, err, endpoint)
62+
}
63+
64+
// sort.Strings sorts in place, returns nothing
65+
sort.Strings(res)
66+
67+
d.SetId(hashcode.Strings(res))
68+
d.Set("result", res)
69+
70+
return nil
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package ovh
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
)
10+
11+
const testAccCloudProjectDatabaseUsersDatasourceConfig_Basic = `
12+
resource "ovh_cloud_project_database" "db" {
13+
service_name = "%s"
14+
engine = "%s"
15+
version = "%s"
16+
plan = "essential"
17+
nodes {
18+
region = "%s"
19+
}
20+
flavor = "%s"
21+
}
22+
23+
resource "ovh_cloud_project_database_user" "user" {
24+
service_name = ovh_cloud_project_database.db.service_name
25+
engine = ovh_cloud_project_database.db.engine
26+
cluster_id = ovh_cloud_project_database.db.id
27+
name = "%s"
28+
}
29+
30+
data "ovh_cloud_project_database_users" "users" {
31+
service_name = ovh_cloud_project_database_user.user.service_name
32+
engine = ovh_cloud_project_database_user.user.engine
33+
cluster_id = ovh_cloud_project_database_user.user.cluster_id
34+
}
35+
`
36+
37+
func TestAccCloudProjectDatabaseUsersDataSource_basic(t *testing.T) {
38+
serviceName := os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST")
39+
engine := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_ENGINE_TEST")
40+
version := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_VERSION_TEST")
41+
region := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_REGION_TEST")
42+
flavor := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_FLAVOR_TEST")
43+
name := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_USER_NAME")
44+
45+
config := fmt.Sprintf(
46+
testAccCloudProjectDatabaseUsersDatasourceConfig_Basic,
47+
serviceName,
48+
engine,
49+
version,
50+
region,
51+
flavor,
52+
name,
53+
)
54+
55+
resource.Test(t, resource.TestCase{
56+
PreCheck: func() { testAccPreCheckCloudDatabaseUser(t) },
57+
Providers: testAccProviders,
58+
Steps: []resource.TestStep{
59+
{
60+
Config: config,
61+
Check: resource.ComposeTestCheckFunc(
62+
resource.TestCheckResourceAttrSet(
63+
"data.ovh_cloud_project_database_users.users",
64+
"result.#",
65+
),
66+
),
67+
},
68+
},
69+
})
70+
}

ovh/provider.go

+3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func Provider() *schema.Provider {
4646
"ovh_cloud_project_containerregistries": dataSourceCloudProjectContainerRegistries(),
4747
"ovh_cloud_project_containerregistry": dataSourceCloudProjectContainerRegistry(),
4848
"ovh_cloud_project_containerregistry_users": dataSourceCloudProjectContainerRegistryUsers(),
49+
"ovh_cloud_project_database_users": dataSourceCloudProjectDatabaseUsers(),
4950
"ovh_cloud_project_failover_ip_attach": dataSourceCloudProjectFailoverIpAttach(),
5051
"ovh_cloud_project_kube": dataSourceCloudProjectKube(),
5152
"ovh_cloud_project_region": dataSourceCloudProjectRegion(),
@@ -87,6 +88,8 @@ func Provider() *schema.Provider {
8788
"ovh_cloud_project_containerregistry": resourceCloudProjectContainerRegistry(),
8889
"ovh_cloud_project_containerregistry_user": resourceCloudProjectContainerRegistryUser(),
8990
"ovh_cloud_project_database": resourceCloudProjectDatabase(),
91+
"ovh_cloud_project_database_user": resourceCloudProjectDatabaseUser(),
92+
"ovh_cloud_project_database_postgresql_user": resourceCloudProjectDatabasepPostgresqlUser(),
9093
"ovh_cloud_project_failover_ip_attach": resourceCloudProjectFailoverIpAttach(),
9194
"ovh_cloud_project_kube": resourceCloudProjectKube(),
9295
"ovh_cloud_project_kube_nodepool": resourceCloudProjectKubeNodePool(),

ovh/provider_test.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,23 @@ func testAccPreCheckCloud(t *testing.T) {
122122

123123
// Checks that the environment variables needed for the /cloud/project/{projectId}/database/ acceptance tests are set.
124124
func testAccPreCheckCloudDatabase(t *testing.T) {
125-
testAccPreCheckCredentials(t)
126-
testAccPreCheckCloud(t)
125+
testAccPreCheckCloudDatabaseNoEngine(t)
127126
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_ENGINE_TEST")
127+
}
128+
129+
// Checks that the environment variables needed for the /cloud/project/{projectId}/database/<engine>/ acceptance tests are set.
130+
func testAccPreCheckCloudDatabaseNoEngine(t *testing.T) {
131+
testAccPreCheckCloud(t)
132+
testAccCheckCloudProjectExists(t)
128133
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_VERSION_TEST")
129134
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_REGION_TEST")
130135
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_FLAVOR_TEST")
136+
}
131137

138+
// Checks that the environment variables needed for the /cloud/project/{projectId}/database/{engine}/{clusterId}/user/ acceptance tests are set.
139+
func testAccPreCheckCloudDatabaseUser(t *testing.T) {
140+
testAccPreCheckCloudDatabase(t)
141+
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_USER_NAME")
132142
}
133143

134144
// Checks that the environment variables needed for the /cloud/project/{projectId}/ip/failover acceptance tests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package ovh
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net/url"
7+
"strings"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
"github.com/ovh/terraform-provider-ovh/ovh/helpers"
11+
)
12+
13+
func resourceCloudProjectDatabasepPostgresqlUser() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceCloudProjectDatabasePostgresqlUserCreate,
16+
Read: resourceCloudProjectDatabasePostgresqlUserRead,
17+
Delete: resourceCloudProjectDatabasePostgresqlUserDelete,
18+
Update: resourceCloudProjectDatabasePostgresqlUserUpdate,
19+
20+
Importer: &schema.ResourceImporter{
21+
State: resourceCloudProjectDatabasePostgresqlUserImportState,
22+
},
23+
24+
Schema: map[string]*schema.Schema{
25+
"service_name": {
26+
Type: schema.TypeString,
27+
ForceNew: true,
28+
Required: true,
29+
DefaultFunc: schema.EnvDefaultFunc("OVH_CLOUD_PROJECT_SERVICE", nil),
30+
},
31+
"cluster_id": {
32+
Type: schema.TypeString,
33+
Description: "Id of the database cluster",
34+
ForceNew: true,
35+
Required: true,
36+
},
37+
"name": {
38+
Type: schema.TypeString,
39+
Description: "Name of the user",
40+
ForceNew: true,
41+
Required: true,
42+
},
43+
"roles": {
44+
Type: schema.TypeList,
45+
Description: "Roles the user belongs to",
46+
Optional: true,
47+
Elem: &schema.Schema{Type: schema.TypeString},
48+
},
49+
50+
//Computed
51+
"created_at": {
52+
Type: schema.TypeString,
53+
Description: "Date of the creation of the cluster",
54+
Computed: true,
55+
},
56+
"password": {
57+
Type: schema.TypeString,
58+
Description: "Password of the user",
59+
Sensitive: true,
60+
Computed: true,
61+
},
62+
"status": {
63+
Type: schema.TypeString,
64+
Description: "Current status of the user",
65+
Computed: true,
66+
},
67+
},
68+
}
69+
}
70+
71+
func resourceCloudProjectDatabasePostgresqlUserImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
72+
givenId := d.Id()
73+
splitId := strings.SplitN(givenId, "/", 3)
74+
if len(splitId) != 3 {
75+
return nil, fmt.Errorf("Import Id is not service_name/cluster_id/id formatted")
76+
}
77+
serviceName := splitId[0]
78+
clusterId := splitId[1]
79+
id := splitId[2]
80+
d.SetId(id)
81+
d.Set("cluster_id", clusterId)
82+
d.Set("service_name", serviceName)
83+
84+
results := make([]*schema.ResourceData, 1)
85+
results[0] = d
86+
return results, nil
87+
}
88+
89+
func resourceCloudProjectDatabasePostgresqlUserCreate(d *schema.ResourceData, meta interface{}) error {
90+
config := meta.(*Config)
91+
serviceName := d.Get("service_name").(string)
92+
clusterId := d.Get("cluster_id").(string)
93+
94+
endpoint := fmt.Sprintf("/cloud/project/%s/database/postgresql/%s/user",
95+
url.PathEscape(serviceName),
96+
url.PathEscape(clusterId),
97+
)
98+
params := (&CloudProjectDatabasePostgresqlUserCreateOpts{}).FromResource(d)
99+
res := &CloudProjectDatabasePostgresqlUserResponse{}
100+
101+
log.Printf("[DEBUG] Will create user: %+v for cluster %s from project %s", params, clusterId, serviceName)
102+
err := config.OVHClient.Post(endpoint, params, res)
103+
if err != nil {
104+
return fmt.Errorf("calling Post %s with params %s:\n\t %q", endpoint, params, err)
105+
}
106+
107+
d.SetId(res.Id)
108+
d.Set("password", res.Password)
109+
110+
return resourceCloudProjectDatabasePostgresqlUserRead(d, meta)
111+
}
112+
113+
func resourceCloudProjectDatabasePostgresqlUserRead(d *schema.ResourceData, meta interface{}) error {
114+
config := meta.(*Config)
115+
serviceName := d.Get("service_name").(string)
116+
clusterId := d.Get("cluster_id").(string)
117+
id := d.Id()
118+
119+
endpoint := fmt.Sprintf("/cloud/project/%s/database/postgresql/%s/user/%s",
120+
url.PathEscape(serviceName),
121+
url.PathEscape(clusterId),
122+
url.PathEscape(id),
123+
)
124+
res := &CloudProjectDatabasePostgresqlUserResponse{}
125+
126+
log.Printf("[DEBUG] Will read user %s from cluster %s from project %s", id, clusterId, serviceName)
127+
if err := config.OVHClient.Get(endpoint, res); err != nil {
128+
return helpers.CheckDeleted(d, err, endpoint)
129+
}
130+
131+
for k, v := range res.ToMap() {
132+
if k != "id" {
133+
d.Set(k, v)
134+
} else {
135+
d.SetId(fmt.Sprint(v))
136+
}
137+
}
138+
139+
log.Printf("[DEBUG] Read user %+v", res)
140+
return nil
141+
}
142+
143+
func resourceCloudProjectDatabasePostgresqlUserUpdate(d *schema.ResourceData, meta interface{}) error {
144+
config := meta.(*Config)
145+
serviceName := d.Get("service_name").(string)
146+
clusterId := d.Get("cluster_id").(string)
147+
id := d.Id()
148+
149+
endpoint := fmt.Sprintf("/cloud/project/%s/database/postgresql/%s/user/%s",
150+
url.PathEscape(serviceName),
151+
url.PathEscape(clusterId),
152+
url.PathEscape(id),
153+
)
154+
params := (&CloudProjectDatabasePostgresqlUserUpdateOpts{}).FromResource(d)
155+
156+
log.Printf("[DEBUG] Will update user: %+v from cluster %s from project %s", params, clusterId, serviceName)
157+
err := config.OVHClient.Put(endpoint, params, nil)
158+
if err != nil {
159+
return fmt.Errorf("calling Put %s with params %v:\n\t %q", endpoint, params, err)
160+
}
161+
162+
return resourceCloudProjectDatabasePostgresqlUserRead(d, meta)
163+
}
164+
165+
func resourceCloudProjectDatabasePostgresqlUserDelete(d *schema.ResourceData, meta interface{}) error {
166+
config := meta.(*Config)
167+
serviceName := d.Get("service_name").(string)
168+
clusterId := d.Get("cluster_id").(string)
169+
id := d.Id()
170+
171+
endpoint := fmt.Sprintf("/cloud/project/%s/database/postgresql/%s/user/%s",
172+
url.PathEscape(serviceName),
173+
url.PathEscape(clusterId),
174+
url.PathEscape(id),
175+
)
176+
177+
log.Printf("[DEBUG] Will delete useruser %s from cluster %s from project %s", id, clusterId, serviceName)
178+
err := config.OVHClient.Delete(endpoint, nil)
179+
if err != nil {
180+
return helpers.CheckDeleted(d, err, endpoint)
181+
}
182+
183+
d.SetId("")
184+
185+
return nil
186+
}

0 commit comments

Comments
 (0)