Skip to content

Commit 87fed1a

Browse files
authored
azurerm_mongo_cluster - add support for the connection_strings attribute (#28880)
1 parent 02bace4 commit 87fed1a

3 files changed

Lines changed: 118 additions & 50 deletions

File tree

internal/services/mongocluster/mongo_cluster_resource.go

Lines changed: 96 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package mongocluster
66
import (
77
"context"
88
"fmt"
9+
"net/url"
910
"regexp"
1011
"time"
1112

@@ -14,7 +15,6 @@ import (
1415
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
1516
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
1617
"github.com/hashicorp/go-azure-sdk/resource-manager/mongocluster/2024-07-01/mongoclusters"
17-
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1818
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
1919
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
2020
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
@@ -27,22 +27,29 @@ var _ sdk.ResourceWithUpdate = MongoClusterResource{}
2727
var _ sdk.ResourceWithCustomizeDiff = MongoClusterResource{}
2828

2929
type MongoClusterResourceModel struct {
30-
Name string `tfschema:"name"`
31-
ResourceGroupName string `tfschema:"resource_group_name"`
32-
Location string `tfschema:"location"`
33-
AdministratorUserName string `tfschema:"administrator_username"`
34-
AdministratorPassword string `tfschema:"administrator_password"`
35-
CreateMode string `tfschema:"create_mode"`
36-
ShardCount int64 `tfschema:"shard_count"`
37-
SourceLocation string `tfschema:"source_location"`
38-
SourceServerId string `tfschema:"source_server_id"`
39-
ComputeTier string `tfschema:"compute_tier"`
40-
HighAvailabilityMode string `tfschema:"high_availability_mode"`
41-
PublicNetworkAccess string `tfschema:"public_network_access"`
42-
PreviewFeatures []string `tfschema:"preview_features"`
43-
StorageSizeInGb int64 `tfschema:"storage_size_in_gb"`
44-
Tags map[string]string `tfschema:"tags"`
45-
Version string `tfschema:"version"`
30+
Name string `tfschema:"name"`
31+
ResourceGroupName string `tfschema:"resource_group_name"`
32+
Location string `tfschema:"location"`
33+
AdministratorUserName string `tfschema:"administrator_username"`
34+
AdministratorPassword string `tfschema:"administrator_password"`
35+
CreateMode string `tfschema:"create_mode"`
36+
ShardCount int64 `tfschema:"shard_count"`
37+
SourceLocation string `tfschema:"source_location"`
38+
SourceServerId string `tfschema:"source_server_id"`
39+
ComputeTier string `tfschema:"compute_tier"`
40+
HighAvailabilityMode string `tfschema:"high_availability_mode"`
41+
PublicNetworkAccess string `tfschema:"public_network_access"`
42+
PreviewFeatures []string `tfschema:"preview_features"`
43+
StorageSizeInGb int64 `tfschema:"storage_size_in_gb"`
44+
ConnectionStrings []MongoClusterConnectionString `tfschema:"connection_strings"`
45+
Tags map[string]string `tfschema:"tags"`
46+
Version string `tfschema:"version"`
47+
}
48+
49+
type MongoClusterConnectionString struct {
50+
Value string `tfschema:"value"`
51+
Description string `tfschema:"description"`
52+
Name string `tfschema:"name"`
4653
}
4754

4855
func (r MongoClusterResource) ModelObject() interface{} {
@@ -57,12 +64,12 @@ func (r MongoClusterResource) ResourceType() string {
5764
return "azurerm_mongo_cluster"
5865
}
5966

60-
func (r MongoClusterResource) Arguments() map[string]*schema.Schema {
61-
return map[string]*schema.Schema{
67+
func (r MongoClusterResource) Arguments() map[string]*pluginsdk.Schema {
68+
return map[string]*pluginsdk.Schema{
6269
"name": {
6370
ForceNew: true,
6471
Required: true,
65-
Type: schema.TypeString,
72+
Type: pluginsdk.TypeString,
6673
ValidateFunc: validation.StringMatch(
6774
regexp.MustCompile(`^[a-z\d]([-a-z\d]{1,38}[a-z\d])$`),
6875
"`name` must be between 3 and 40 characters. It can contain only lowercase letters, numbers, and hyphens (-). It must start and end with a lowercase letter or number.",
@@ -74,15 +81,15 @@ func (r MongoClusterResource) Arguments() map[string]*schema.Schema {
7481
"location": commonschema.Location(),
7582

7683
"administrator_username": {
77-
Type: schema.TypeString,
84+
Type: pluginsdk.TypeString,
7885
Optional: true,
7986
ForceNew: true,
8087
ValidateFunc: validation.StringIsNotEmpty,
8188
RequiredWith: []string{"administrator_password"},
8289
},
8390

8491
"create_mode": {
85-
Type: schema.TypeString,
92+
Type: pluginsdk.TypeString,
8693
Optional: true,
8794
ForceNew: true,
8895
Default: string(mongoclusters.CreateModeDefault),
@@ -94,24 +101,24 @@ func (r MongoClusterResource) Arguments() map[string]*schema.Schema {
94101
},
95102

96103
"preview_features": {
97-
Type: schema.TypeList,
104+
Type: pluginsdk.TypeList,
98105
Optional: true,
99106
ForceNew: true,
100-
Elem: &schema.Schema{
101-
Type: schema.TypeString,
107+
Elem: &pluginsdk.Schema{
108+
Type: pluginsdk.TypeString,
102109
ValidateFunc: validation.StringInSlice(mongoclusters.PossibleValuesForPreviewFeature(), false),
103110
},
104111
},
105112

106113
"shard_count": {
107-
Type: schema.TypeInt,
114+
Type: pluginsdk.TypeInt,
108115
Optional: true,
109116
ValidateFunc: validation.IntAtLeast(1),
110117
ForceNew: true,
111118
},
112119

113120
"source_location": {
114-
Type: schema.TypeString,
121+
Type: pluginsdk.TypeString,
115122
Optional: true,
116123
ForceNew: true,
117124
StateFunc: location.StateFunc,
@@ -121,22 +128,22 @@ func (r MongoClusterResource) Arguments() map[string]*schema.Schema {
121128
},
122129

123130
"source_server_id": {
124-
Type: schema.TypeString,
131+
Type: pluginsdk.TypeString,
125132
Optional: true,
126133
ForceNew: true,
127134
ValidateFunc: mongoclusters.ValidateMongoClusterID,
128135
},
129136

130137
"administrator_password": {
131-
Type: schema.TypeString,
138+
Type: pluginsdk.TypeString,
132139
Optional: true,
133140
Sensitive: true,
134141
ValidateFunc: validation.StringIsNotEmpty,
135142
RequiredWith: []string{"administrator_username"},
136143
},
137144

138145
"compute_tier": {
139-
Type: schema.TypeString,
146+
Type: pluginsdk.TypeString,
140147
Optional: true,
141148
ValidateFunc: validation.StringInSlice([]string{
142149
"Free",
@@ -150,7 +157,7 @@ func (r MongoClusterResource) Arguments() map[string]*schema.Schema {
150157
},
151158

152159
"high_availability_mode": {
153-
Type: schema.TypeString,
160+
Type: pluginsdk.TypeString,
154161
Optional: true,
155162
ValidateFunc: validation.StringInSlice([]string{
156163
// Confirmed with service team the `SameZone` is currently not supported.
@@ -160,22 +167,22 @@ func (r MongoClusterResource) Arguments() map[string]*schema.Schema {
160167
},
161168

162169
"public_network_access": {
163-
Type: schema.TypeString,
170+
Type: pluginsdk.TypeString,
164171
Optional: true,
165172
Default: string(mongoclusters.PublicNetworkAccessEnabled),
166173
ValidateFunc: validation.StringInSlice(mongoclusters.PossibleValuesForPublicNetworkAccess(), false),
167174
},
168175

169176
"storage_size_in_gb": {
170-
Type: schema.TypeInt,
177+
Type: pluginsdk.TypeInt,
171178
Optional: true,
172179
ValidateFunc: validation.IntBetween(32, 16384),
173180
},
174181

175182
"tags": commonschema.Tags(),
176183

177184
"version": {
178-
Type: schema.TypeString,
185+
Type: pluginsdk.TypeString,
179186
Optional: true,
180187
ValidateFunc: validation.StringInSlice([]string{
181188
"5.0",
@@ -186,8 +193,30 @@ func (r MongoClusterResource) Arguments() map[string]*schema.Schema {
186193
}
187194
}
188195

189-
func (r MongoClusterResource) Attributes() map[string]*schema.Schema {
190-
return map[string]*schema.Schema{}
196+
func (r MongoClusterResource) Attributes() map[string]*pluginsdk.Schema {
197+
return map[string]*pluginsdk.Schema{
198+
"connection_strings": {
199+
Type: pluginsdk.TypeList,
200+
Sensitive: true,
201+
Computed: true,
202+
Elem: &pluginsdk.Resource{
203+
Schema: map[string]*pluginsdk.Schema{
204+
"name": {
205+
Type: pluginsdk.TypeString,
206+
Computed: true,
207+
},
208+
"description": {
209+
Type: pluginsdk.TypeString,
210+
Computed: true,
211+
},
212+
"value": {
213+
Type: pluginsdk.TypeString,
214+
Computed: true,
215+
},
216+
},
217+
},
218+
},
219+
}
191220
}
192221

193222
func (r MongoClusterResource) Create() sdk.ResourceFunc {
@@ -452,6 +481,14 @@ func (r MongoClusterResource) Read() sdk.ResourceFunc {
452481
state.Tags = pointer.From(model.Tags)
453482
}
454483

484+
csResp, err := client.ListConnectionStrings(ctx, *id)
485+
if err != nil {
486+
return fmt.Errorf("listing connection strings for %s: %+v", *id, err)
487+
}
488+
if model := csResp.Model; model != nil {
489+
state.ConnectionStrings = flattenMongoClusterConnectionStrings(model.ConnectionStrings, state.AdministratorUserName, state.AdministratorPassword)
490+
}
491+
455492
return metadata.Encode(&state)
456493
},
457494
}
@@ -570,3 +607,26 @@ func flattenMongoClusterPreviewFeatures(input *[]mongoclusters.PreviewFeature) [
570607

571608
return results
572609
}
610+
611+
func flattenMongoClusterConnectionStrings(input *[]mongoclusters.ConnectionString, userName, userPassword string) []MongoClusterConnectionString {
612+
results := make([]MongoClusterConnectionString, 0)
613+
if input == nil {
614+
return results
615+
}
616+
for _, cs := range *input {
617+
value := pointer.From(cs.ConnectionString)
618+
// Password can be empty if it isn't available in the state file (e.g. during import).
619+
// In this case, we simply leave the placeholder unchanged.
620+
if userPassword != "" {
621+
value = regexp.MustCompile(`<user>:<password>`).ReplaceAllString(value, url.UserPassword(userName, userPassword).String())
622+
}
623+
624+
results = append(results, MongoClusterConnectionString{
625+
Name: pointer.From(cs.Name),
626+
Description: pointer.From(cs.Description),
627+
Value: value,
628+
})
629+
}
630+
631+
return results
632+
}

internal/services/mongocluster/mongo_cluster_resource_test.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ func testAccMongoCluster_basic(t *testing.T) {
3636
Config: r.basic(data),
3737
Check: acceptance.ComposeTestCheckFunc(
3838
check.That(data.ResourceName).ExistsInAzure(r),
39+
check.That(data.ResourceName).Key("connection_strings.0.value").HasValue(
40+
fmt.Sprintf(`mongodb+srv://adminTerraform:QAZwsx123basic@acctest-mc%d.mongocluster.cosmos.azure.com/?tls=true&authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000`,
41+
data.RandomInteger)),
3942
),
4043
},
41-
data.ImportStep("administrator_password", "create_mode"),
44+
data.ImportStep("administrator_password", "create_mode", "connection_strings.0.value"),
4245
})
4346
}
4447

@@ -53,14 +56,14 @@ func testAccMongoCluster_update(t *testing.T) {
5356
check.That(data.ResourceName).ExistsInAzure(r),
5457
),
5558
},
56-
data.ImportStep("administrator_password", "create_mode"),
59+
data.ImportStep("administrator_password", "create_mode", "connection_strings.0.value"),
5760
{
5861
Config: r.update(data),
5962
Check: acceptance.ComposeTestCheckFunc(
6063
check.That(data.ResourceName).ExistsInAzure(r),
6164
),
6265
},
63-
data.ImportStep("administrator_password", "create_mode"),
66+
data.ImportStep("administrator_password", "create_mode", "connection_strings.0.value"),
6467
})
6568
}
6669

@@ -90,14 +93,14 @@ func TestAccMongoCluster_previewFeature(t *testing.T) {
9093
check.That(data.ResourceName).ExistsInAzure(r),
9194
),
9295
},
93-
data.ImportStep("administrator_password", "create_mode"),
96+
data.ImportStep("administrator_password", "create_mode", "connection_strings.0.value", "connection_strings.1.value"),
9497
{
9598
Config: r.geoReplica(data),
9699
Check: acceptance.ComposeTestCheckFunc(
97100
check.That(data.ResourceName).ExistsInAzure(r),
98101
),
99102
},
100-
data.ImportStep("administrator_password", "create_mode", "source_location"),
103+
data.ImportStep("administrator_password", "create_mode", "source_location", "connection_strings.0.value", "connection_strings.1.value"),
101104
})
102105
}
103106

@@ -112,7 +115,7 @@ func TestAccMongoCluster_geoReplica(t *testing.T) {
112115
check.That(data.ResourceName).ExistsInAzure(r),
113116
),
114117
},
115-
data.ImportStep("administrator_password", "create_mode", "source_location"),
118+
data.ImportStep("administrator_password", "create_mode", "source_location", "connection_strings.0.value", "connection_strings.1.value"),
116119
})
117120
}
118121

@@ -134,19 +137,12 @@ func (r MongoClusterResource) basic(data acceptance.TestData) string {
134137
return fmt.Sprintf(`
135138
%s
136139
137-
resource "random_password" "test" {
138-
length = 8
139-
numeric = true
140-
upper = true
141-
lower = true
142-
}
143-
144140
resource "azurerm_mongo_cluster" "test" {
145141
name = "acctest-mc%d"
146142
resource_group_name = azurerm_resource_group.test.name
147143
location = azurerm_resource_group.test.location
148144
administrator_username = "adminTerraform"
149-
administrator_password = random_password.test.result
145+
administrator_password = "QAZwsx123basic"
150146
shard_count = "1"
151147
compute_tier = "Free"
152148
high_availability_mode = "Disabled"

website/docs/r/mongo_cluster.html.markdown

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ In addition to the Arguments listed above - the following Attributes are exporte
111111

112112
* `id` - The ID of the MongoDB Cluster.
113113

114+
* `connection_strings` - The list of `connection_strings` blocks as defined below.
115+
116+
---
117+
118+
A `connection_strings` exports the following:
119+
120+
* `name` - The name of the connection string.
121+
122+
* `description` - The description of the connection string.
123+
124+
* `value` - The value of the Mongo Cluster connection string. The `<user>:<password>` placeholder returned from API will be replaced by the real `administrator_username` and `administrator_password` if available in the state.
125+
114126
## Timeouts
115127

116128
The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions:

0 commit comments

Comments
 (0)