From 3b3761a94156a36f0293b8a8b209c8a41a8e4c3d Mon Sep 17 00:00:00 2001 From: Junio Cezar Date: Mon, 29 Jan 2024 18:03:11 -0300 Subject: [PATCH 1/5] ENG-13251: Add MongoDB Flavor to Repo Configuration --- .../repository/resource_cyral_repository.go | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cyral/internal/repository/resource_cyral_repository.go b/cyral/internal/repository/resource_cyral_repository.go index d594c08e..e04d0278 100644 --- a/cyral/internal/repository/resource_cyral_repository.go +++ b/cyral/internal/repository/resource_cyral_repository.go @@ -32,6 +32,7 @@ const ( RepoMongoDBReplicaSetNameKey = "replica_set_name" RepoMongoDBServerTypeKey = "server_type" RepoMongoDBSRVRecordName = "srv_record_name" + RepoMongoDBFlavorKey = "flavor" ) const ( @@ -76,6 +77,12 @@ const ( Sharded = "sharded" ) +const ( + MongoDBFlavorMongoDB = "mongodb" + MongoDBFlavorDocumentDB = "documentdb" + MongoDBFlavorDefault = "" +) + func mongoServerTypes() []string { return []string{ ReplicaSet, @@ -84,6 +91,14 @@ func mongoServerTypes() []string { } } +func mongoFlavors() []string { + return []string{ + MongoDBFlavorMongoDB, + MongoDBFlavorDocumentDB, + MongoDBFlavorDefault, + } +} + type RepoInfo struct { ID string `json:"id"` Name string `json:"name"` @@ -109,6 +124,7 @@ type MongoDBSettings struct { ReplicaSetName string `json:"replicaSetName,omitempty"` ServerType string `json:"serverType,omitempty"` SRVRecordName string `json:"srvRecordName,omitempty"` + Flavor string `json:"flavor,omitempty"` } type RepoNode struct { @@ -467,6 +483,14 @@ func ResourceRepository() *schema.Resource { Type: schema.TypeString, Optional: true, }, + RepoMongoDBFlavorKey: { + Description: "The flavor of the MongoDB deployment. Allowed values: " + utils.SupportedValuesAsMarkdown(mongoFlavors()) + + "\n\n The following conditions apply:\n" + + " - The `" + MongoDBFlavorDocumentDB + "` flavor cannot be combined with the MongoDB Server type `" + Sharded + "`.\n", + Type: schema.TypeString, + Required: false, + ValidateFunc: validation.StringInSlice(mongoFlavors(), false), + }, }, }, }, From 1c88fa812fc312ca0ad9284507ec397d3cd87442 Mon Sep 17 00:00:00 2001 From: Junio Cezar Date: Mon, 29 Jan 2024 18:29:10 -0300 Subject: [PATCH 2/5] Run documentation script --- .../repository/resource_cyral_repository.go | 14 +++++++-- docker-compose.yaml | 2 ++ docs/resources/repository.md | 31 ++++++++++--------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/cyral/internal/repository/resource_cyral_repository.go b/cyral/internal/repository/resource_cyral_repository.go index e04d0278..f6354fb7 100644 --- a/cyral/internal/repository/resource_cyral_repository.go +++ b/cyral/internal/repository/resource_cyral_repository.go @@ -80,7 +80,6 @@ const ( const ( MongoDBFlavorMongoDB = "mongodb" MongoDBFlavorDocumentDB = "documentdb" - MongoDBFlavorDefault = "" ) func mongoServerTypes() []string { @@ -95,7 +94,6 @@ func mongoFlavors() []string { return []string{ MongoDBFlavorMongoDB, MongoDBFlavorDocumentDB, - MongoDBFlavorDefault, } } @@ -253,6 +251,7 @@ func (r *RepoInfo) MongoDBSettingsAsInterface() []interface{} { RepoMongoDBReplicaSetNameKey: r.MongoDBSettings.ReplicaSetName, RepoMongoDBServerTypeKey: r.MongoDBSettings.ServerType, RepoMongoDBSRVRecordName: r.MongoDBSettings.SRVRecordName, + RepoMongoDBFlavorKey: r.MongoDBSettings.Flavor, }} } @@ -263,6 +262,7 @@ func (r *RepoInfo) MongoDBSettingsFromInterface(i []interface{}) error { var replicaSetName = i[0].(map[string]interface{})[RepoMongoDBReplicaSetNameKey].(string) var serverType = i[0].(map[string]interface{})[RepoMongoDBServerTypeKey].(string) var srvRecordName = i[0].(map[string]interface{})[RepoMongoDBSRVRecordName].(string) + var mongoFlavor = i[0].(map[string]interface{})[RepoMongoDBFlavorKey].(string) if serverType == ReplicaSet && replicaSetName == "" { return fmt.Errorf("'%s' must be provided when '%s=\"%s\"'", RepoMongoDBReplicaSetNameKey, RepoMongoDBServerTypeKey, ReplicaSet) @@ -279,10 +279,18 @@ func (r *RepoInfo) MongoDBSettingsFromInterface(i []interface{}) error { Standalone, ) } + if serverType == Sharded && mongoFlavor == MongoDBFlavorDocumentDB { + return fmt.Errorf( + "%q MongoDB flavor cannot be combined with server type: %q. For configuring "+ + "DocumentDB Elastic clusters, please use the %s server type", + MongoDBFlavorDocumentDB, Sharded, Standalone, + ) + } r.MongoDBSettings = &MongoDBSettings{ ReplicaSetName: i[0].(map[string]interface{})[RepoMongoDBReplicaSetNameKey].(string), ServerType: i[0].(map[string]interface{})[RepoMongoDBServerTypeKey].(string), SRVRecordName: i[0].(map[string]interface{})[RepoMongoDBSRVRecordName].(string), + Flavor: i[0].(map[string]interface{})[RepoMongoDBFlavorKey].(string), } return nil } @@ -488,7 +496,7 @@ func ResourceRepository() *schema.Resource { "\n\n The following conditions apply:\n" + " - The `" + MongoDBFlavorDocumentDB + "` flavor cannot be combined with the MongoDB Server type `" + Sharded + "`.\n", Type: schema.TypeString, - Required: false, + Optional: true, ValidateFunc: validation.StringInSlice(mongoFlavors(), false), }, }, diff --git a/docker-compose.yaml b/docker-compose.yaml index fbdeed5c..f62f02d5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,6 +4,8 @@ services: app: image: golang:1.21 container_name: terraform_provider_cyral + environment: + - GOFLAGS=-buildvcs=false volumes: - .:/go/src/terraform-provider-cyral working_dir: /go/src/terraform-provider-cyral diff --git a/docs/resources/repository.md b/docs/resources/repository.md index 514fc39f..c65564dd 100644 --- a/docs/resources/repository.md +++ b/docs/resources/repository.md @@ -10,9 +10,8 @@ This module provides the repository configuration options as shown in Cyral UI. ## Example Usage More complex examples using `cyral_repository` resource are available in the `Guides` section: - -- [Create an AWS EC2 sidecar to protect PostgreSQL and MySQL databases](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/setup_cp_and_deploy_sidecar) -- [Setup SSO access to MongoDB cluster using Okta IdP](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/mongodb_cluster_okta_idp) +* [Create an AWS EC2 sidecar to protect PostgreSQL and MySQL databases](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/setup_cp_and_deploy_sidecar) +* [Setup SSO access to MongoDB cluster using Okta IdP](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/mongodb_cluster_okta_idp) ```terraform ### Minimal Repository @@ -84,7 +83,6 @@ resource "cyral_repository" "multi_node_mongo_repo" { ``` - ## Schema ### Required @@ -118,14 +116,13 @@ resource "cyral_repository" "multi_node_mongo_repo" { - `id` (String) ID of this resource in Cyral environment. - ### Nested Schema for `repo_node` Optional: -- `dynamic` (Boolean) _Only supported for MongoDB in cluster configurations._ - Indicates if the node is dynamically discovered, meaning that the sidecar will query the cluster to get the topology information and discover the addresses of the dynamic nodes. If set to `true`, `host` and `port` must be empty. A node with value of this field as false considered `static`. - The following conditions apply: +- `dynamic` (Boolean) *Only supported for MongoDB in cluster configurations.* +Indicates if the node is dynamically discovered, meaning that the sidecar will query the cluster to get the topology information and discover the addresses of the dynamic nodes. If set to `true`, `host` and `port` must be empty. A node with value of this field as false considered `static`. +The following conditions apply: - The total number of declared `repo_node` blocks must match the actual number of nodes in the cluster. - If there are static nodes in the configuration, they must be declared before all dynamic nodes. - See the MongoDB-specific configuration in the [mongodb_settings](#nested-schema-for-mongodb_settings). @@ -133,8 +130,8 @@ Optional: - `name` (String) Name of the repo node. - `port` (Number) Repository access port (ex: `3306`). Can be empty if node is dynamic. - + ### Nested Schema for `connection_draining` Optional: @@ -142,27 +139,31 @@ Optional: - `auto` (Boolean) Whether connections should be drained automatically after a listener dies. - `wait_time` (Number) Seconds to wait to let connections drain before starting to kill all the connections, if auto is set to true. - + ### Nested Schema for `mongodb_settings` Required: -- `server_type` (String) Type of the MongoDB server. Allowed values: - +- `server_type` (String) Type of the MongoDB server. Allowed values: - `replicaset` - `standalone` - `sharded` The following conditions apply: - - - If `sharded` and `srv_record_name` _not_ provided, then all `repo_node` blocks must be static (see [`dynamic`](#dynamic)). + - If `sharded` and `srv_record_name` *not* provided, then all `repo_node` blocks must be static (see [`dynamic`](#dynamic)). - If `sharded` and `srv_record_name` provided, then all `repo_node` blocks must be dynamic (see [`dynamic`](#dynamic)). - If `standalone`, then only one `repo_node` block can be declared and it must be static (see [`dynamic`](#dynamic)). The `srv_record_name` is not supported in this configuration. - - If `replicaset` and `srv_record_name` _not_ provided, then `repo_node` blocks may mix dynamic and static nodes (see [`dynamic`](#dynamic)). + - If `replicaset` and `srv_record_name` *not* provided, then `repo_node` blocks may mix dynamic and static nodes (see [`dynamic`](#dynamic)). - If `replicaset` and `srv_record_name` provided, then `repo_node` blocks must be dynamic (see [`dynamic`](#dynamic)). Optional: +- `flavor` (String) The flavor of the MongoDB deployment. Allowed values: + - `mongodb` + - `documentdb` + + The following conditions apply: + - The `documentdb` flavor cannot be combined with the MongoDB Server type `sharded`. - `replica_set_name` (String) Name of the replica set, if applicable. - `srv_record_name` (String) Name of a DNS SRV record which contains cluster topology details. If specified, then all `repo_node` blocks must be declared dynamic (see [`dynamic`](#dynamic)). Only supported for `server_type="sharded"` or `server_type="replicaset". From 982edc7bdf1cfada5284646c845244ae84f72375 Mon Sep 17 00:00:00 2001 From: Junio Cezar Date: Mon, 29 Jan 2024 18:30:51 -0300 Subject: [PATCH 3/5] precommit changes --- docs/resources/repository.md | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/docs/resources/repository.md b/docs/resources/repository.md index c65564dd..a1cbf55f 100644 --- a/docs/resources/repository.md +++ b/docs/resources/repository.md @@ -10,8 +10,9 @@ This module provides the repository configuration options as shown in Cyral UI. ## Example Usage More complex examples using `cyral_repository` resource are available in the `Guides` section: -* [Create an AWS EC2 sidecar to protect PostgreSQL and MySQL databases](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/setup_cp_and_deploy_sidecar) -* [Setup SSO access to MongoDB cluster using Okta IdP](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/mongodb_cluster_okta_idp) + +- [Create an AWS EC2 sidecar to protect PostgreSQL and MySQL databases](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/setup_cp_and_deploy_sidecar) +- [Setup SSO access to MongoDB cluster using Okta IdP](https://registry.terraform.io/providers/cyralinc/cyral/latest/docs/guides/mongodb_cluster_okta_idp) ```terraform ### Minimal Repository @@ -83,6 +84,7 @@ resource "cyral_repository" "multi_node_mongo_repo" { ``` + ## Schema ### Required @@ -116,13 +118,14 @@ resource "cyral_repository" "multi_node_mongo_repo" { - `id` (String) ID of this resource in Cyral environment. + ### Nested Schema for `repo_node` Optional: -- `dynamic` (Boolean) *Only supported for MongoDB in cluster configurations.* -Indicates if the node is dynamically discovered, meaning that the sidecar will query the cluster to get the topology information and discover the addresses of the dynamic nodes. If set to `true`, `host` and `port` must be empty. A node with value of this field as false considered `static`. -The following conditions apply: +- `dynamic` (Boolean) _Only supported for MongoDB in cluster configurations._ + Indicates if the node is dynamically discovered, meaning that the sidecar will query the cluster to get the topology information and discover the addresses of the dynamic nodes. If set to `true`, `host` and `port` must be empty. A node with value of this field as false considered `static`. + The following conditions apply: - The total number of declared `repo_node` blocks must match the actual number of nodes in the cluster. - If there are static nodes in the configuration, they must be declared before all dynamic nodes. - See the MongoDB-specific configuration in the [mongodb_settings](#nested-schema-for-mongodb_settings). @@ -130,8 +133,8 @@ The following conditions apply: - `name` (String) Name of the repo node. - `port` (Number) Repository access port (ex: `3306`). Can be empty if node is dynamic. - + ### Nested Schema for `connection_draining` Optional: @@ -139,31 +142,36 @@ Optional: - `auto` (Boolean) Whether connections should be drained automatically after a listener dies. - `wait_time` (Number) Seconds to wait to let connections drain before starting to kill all the connections, if auto is set to true. - + ### Nested Schema for `mongodb_settings` Required: -- `server_type` (String) Type of the MongoDB server. Allowed values: +- `server_type` (String) Type of the MongoDB server. Allowed values: + - `replicaset` - `standalone` - `sharded` The following conditions apply: - - If `sharded` and `srv_record_name` *not* provided, then all `repo_node` blocks must be static (see [`dynamic`](#dynamic)). + + - If `sharded` and `srv_record_name` _not_ provided, then all `repo_node` blocks must be static (see [`dynamic`](#dynamic)). - If `sharded` and `srv_record_name` provided, then all `repo_node` blocks must be dynamic (see [`dynamic`](#dynamic)). - If `standalone`, then only one `repo_node` block can be declared and it must be static (see [`dynamic`](#dynamic)). The `srv_record_name` is not supported in this configuration. - - If `replicaset` and `srv_record_name` *not* provided, then `repo_node` blocks may mix dynamic and static nodes (see [`dynamic`](#dynamic)). + - If `replicaset` and `srv_record_name` _not_ provided, then `repo_node` blocks may mix dynamic and static nodes (see [`dynamic`](#dynamic)). - If `replicaset` and `srv_record_name` provided, then `repo_node` blocks must be dynamic (see [`dynamic`](#dynamic)). Optional: -- `flavor` (String) The flavor of the MongoDB deployment. Allowed values: +- `flavor` (String) The flavor of the MongoDB deployment. Allowed values: + - `mongodb` - `documentdb` The following conditions apply: + - The `documentdb` flavor cannot be combined with the MongoDB Server type `sharded`. + - `replica_set_name` (String) Name of the replica set, if applicable. - `srv_record_name` (String) Name of a DNS SRV record which contains cluster topology details. If specified, then all `repo_node` blocks must be declared dynamic (see [`dynamic`](#dynamic)). Only supported for `server_type="sharded"` or `server_type="replicaset". From 26ce92ec20adede22a575c34f92f2554d17d62eb Mon Sep 17 00:00:00 2001 From: Junio Cezar Date: Tue, 30 Jan 2024 16:17:29 -0300 Subject: [PATCH 4/5] Update some tests --- .../repository/resource_cyral_repository_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cyral/internal/repository/resource_cyral_repository_test.go b/cyral/internal/repository/resource_cyral_repository_test.go index bca4824c..5ce9a2e7 100644 --- a/cyral/internal/repository/resource_cyral_repository_test.go +++ b/cyral/internal/repository/resource_cyral_repository_test.go @@ -115,6 +115,7 @@ var ( MongoDBSettings: &repository.MongoDBSettings{ ReplicaSetName: "some-replica-set", ServerType: repository.ReplicaSet, + Flavor: "mongodb", }, } @@ -136,6 +137,7 @@ var ( ReplicaSetName: "myReplicaSet", ServerType: "replicaset", SRVRecordName: "mySRVRecord", + Flavor: "documentdb", }, } ) @@ -236,6 +238,13 @@ func repoCheckFuctions(repo repository.RepoInfo, resName string) resource.TestCh repo.MongoDBSettings.ReplicaSetName), }...) } + if repo.MongoDBSettings.Flavor != "" { + checkFuncs = append(checkFuncs, []resource.TestCheckFunc{ + resource.TestCheckResourceAttr(resourceFullName, + "mongodb_settings.0.flavor", + repo.MongoDBSettings.Flavor), + }...) + } checkFuncs = append(checkFuncs, []resource.TestCheckFunc{ resource.TestCheckResourceAttr(resourceFullName, "mongodb_settings.0.server_type", From f1ca1038188b931a8b349b06a625d2400fe80bae Mon Sep 17 00:00:00 2001 From: Junio Cezar Date: Tue, 30 Jan 2024 19:39:36 -0300 Subject: [PATCH 5/5] Remove local validation, leave it to API --- cyral/internal/repository/resource_cyral_repository.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cyral/internal/repository/resource_cyral_repository.go b/cyral/internal/repository/resource_cyral_repository.go index f6354fb7..1d1631fb 100644 --- a/cyral/internal/repository/resource_cyral_repository.go +++ b/cyral/internal/repository/resource_cyral_repository.go @@ -262,7 +262,6 @@ func (r *RepoInfo) MongoDBSettingsFromInterface(i []interface{}) error { var replicaSetName = i[0].(map[string]interface{})[RepoMongoDBReplicaSetNameKey].(string) var serverType = i[0].(map[string]interface{})[RepoMongoDBServerTypeKey].(string) var srvRecordName = i[0].(map[string]interface{})[RepoMongoDBSRVRecordName].(string) - var mongoFlavor = i[0].(map[string]interface{})[RepoMongoDBFlavorKey].(string) if serverType == ReplicaSet && replicaSetName == "" { return fmt.Errorf("'%s' must be provided when '%s=\"%s\"'", RepoMongoDBReplicaSetNameKey, RepoMongoDBServerTypeKey, ReplicaSet) @@ -279,13 +278,6 @@ func (r *RepoInfo) MongoDBSettingsFromInterface(i []interface{}) error { Standalone, ) } - if serverType == Sharded && mongoFlavor == MongoDBFlavorDocumentDB { - return fmt.Errorf( - "%q MongoDB flavor cannot be combined with server type: %q. For configuring "+ - "DocumentDB Elastic clusters, please use the %s server type", - MongoDBFlavorDocumentDB, Sharded, Standalone, - ) - } r.MongoDBSettings = &MongoDBSettings{ ReplicaSetName: i[0].(map[string]interface{})[RepoMongoDBReplicaSetNameKey].(string), ServerType: i[0].(map[string]interface{})[RepoMongoDBServerTypeKey].(string),