diff --git a/CHANGELOG.md b/CHANGELOG.md index b8497fb5d8..83b60a1b62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,30 @@ # Changelog + +## [v1.4.0-pre.1](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/v1.4.0-pre.1) (2022-06-29) +**Closed issues:** + +Fix for Add support for cloud export backup to mongodbatlas_cloud_backup_schedule (#740) +Feature Add: Update the project resource with new settings (#741) +Feature Add: Feature add: Add support for management of federated authentication configuration +Feature Add: Add Regionalized Private Endpoint Settings +Fix for Potential bug when disabling auditing #705 +Feature Add: Prometheus and Microsoft Team to the Third Party Integration Settings #706 +Fix for Correct import function for snapshot export bucket #714 #715 +Fix for Add support for schema migration #717 +Feature Add: Prometheus and Microsoft Team to the Third Party Integration Settings +Fix for Cannot import export bucket - bad state id encoding #708 +Error missing expected { when updating the provider #697 + +**Merged pull requests:** + +INTMDB-321: Add support for cloud export backup to mongodbatlas_cloud_backup_schedule (#740) +INTMDB-313: Update the project resource with new settings (#741) +INTMDB-301: Feature add: Add support for management of federated authentication configuration +INTMDB-307: Add Regionalized Private Endpoint Settings +INTMDB-310: Potential bug when disabling auditing #705 +INTMDB-311: Feature Add: Prometheus and Microsoft Team to the Third Party Integration Settings #706 +INTMDB-315: Correct import function for snapshot export bucket #714 #715 +INTMDB-309: Add support for schema migration #717 ## [v1.3.1-pre.1](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/v1.3.1-pre.1) (2022-02-23) **Closed issues:** diff --git a/README.md b/README.md index 168fc04712..b4406f78c6 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,19 @@ $ export MONGODB_ATLAS_API_KEYS_IDS= export SKIP_TEST_EXTERNAL_CREDENTIALS=TRUE ``` +- For `Federated Settings` resource configuration: +```sh +$ export MONGODB_ATLAS_FEDERATION_SETTINGS_ID= +$ export ONGODB_ATLAS_FEDERATED_ORG_ID= +$ export MONGODB_ATLAS_FEDERATED_PROJECT_ID= +$ export MONGODB_ATLAS_FEDERATED_GROUP_ID= +$ export MONGODB_ATLAS_FEDERATED_ROLE_MAPPING_ID= +$ export MONGODB_ATLAS_FEDERATED_OKTA_IDP_ID= +$ export MONGODB_ATLAS_FEDERATED_SSO_URL= +$ export MONGODB_ATLAS_FEDERATED_ISSUER_URI= +``` +~> **Notice:** For more information about the Federation configuration resource, see: https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/ + ##### AWS env variables - For `Network Peering` resource configuration: diff --git a/examples/Federated-Settings/Readme.md b/examples/Federated-Settings/Readme.md new file mode 100644 index 0000000000..c536c0cfa8 --- /dev/null +++ b/examples/Federated-Settings/Readme.md @@ -0,0 +1,59 @@ +# Example - Okta and MongoDB Atlas Federated Settings Configuration + +This project aims to provide an example of using Okta and MongoDB Atlas together. + + +## Dependencies + +* Terraform v0.13 +* Okta account +* A MongoDB Atlas account + +``` +Terraform v0.13.0 ++ provider registry.terraform.io/terraform-providers/mongodbatlas v1.4.0 +``` + +## Usage + +**1\. Ensure your Okta/Mongodb Atlas Federal settings configuration is set up to have a working set of organizations, verified domains, and identity providers.** + +**2\. TFVARS** + +Now create **terraform.tfvars** file with all the variable values and make sure **not to commit it**. + +**3\. Review the Terraform plan. ** + +Execute the below command and ensure you are happy with the plan. + +``` bash +$ terraform plan +``` +This project currently does the below deployments: + +- MongoDB Atlas Federated Settings Organizational Role Mapping +- MongoDB Atlas Federated Settings Organizational Identity Provider +- MongoDB Atlas Federated Settings Organizational configuration + +**4\. Execute the Terraform import for 2 resources that do not support create.** +``` bash +$ terraform import mongodbatlas_federated_settings_identity_provider.identity_provider 6287a67f7f7f7f7f441c6c-0oad7f7f7f7fk1297 + terraform import mongodbatlas_federated_settings_org_config.org_connections_import 6287a67f7f7f7f7f441c6c-627a96837f7f7f7f7e306f14 + +``` + +**5\. Execute the Terraform apply.** + +Now execute the plan to provision the Federated settings resources. + +``` bash +$ terraform apply +``` + +**6\. Destroy the resources.** + +Once you are finished your testing, ensure you destroy the resources to avoid unnecessary Atlas charges. + +``` bash +$ terraform destroy +``` diff --git a/examples/Federated-Settings/main.tf b/examples/Federated-Settings/main.tf new file mode 100644 index 0000000000..c35ec1488f --- /dev/null +++ b/examples/Federated-Settings/main.tf @@ -0,0 +1,50 @@ +data "mongodbatlas_federated_settings" "federated_settings" { + org_id = var.org_id +} +data "mongodbatlas_federated_settings_identity_providers" "identity_provider" { + federation_settings_id = data.mongodbatlas_federated_settings.federated_settings.id +} + +data "mongodbatlas_federated_settings_org_configs" "org_configs_ds" { + federation_settings_id = data.mongodbatlas_federated_settings.federated_settings.id +} + +data "mongodbatlas_federated_settings_org_role_mappings" "org_role_mapping" { + federation_settings_id = data.mongodbatlas_federated_settings.federated_settings.id + org_id = var.org_id +} +resource "mongodbatlas_federated_settings_org_role_mapping" "org_role_mapping" { + federation_settings_id = data.mongodbatlas_federated_settings.federated_settings.id + org_id = var.org_id + external_group_name = "newgroup" + + role_assignments { + group_id = var.group_id + roles = ["GROUP_OWNER", "GROUP_DATA_ACCESS_ADMIN", "GROUP_SEARCH_INDEX_EDITOR", "GROUP_DATA_ACCESS_READ_ONLY"] + } + + role_assignments { + org_id = var.org_id + roles = ["ORG_OWNER", "ORG_MEMBER"] + } + +} +resource "mongodbatlas_federated_settings_org_config" "org_connections_import" { + federation_settings_id = data.mongodbatlas_federated_settings.federated_settings.id + org_id = var.org_id + identity_provider_id = var.identity_provider_id + domain_restriction_enabled = false + domain_allow_list = ["yourdomain.com"] +} + +resource "mongodbatlas_federated_settings_identity_provider" "identity_provider" { + federation_settings_id = data.mongodbatlas_federated_settings.federated_settings.id + name = var.name + associated_domains = ["yourdomain.com"] + sso_debug_enabled = true + status = "ACTIVE" + sso_url = "https://mysso.oktapreview.com/app/mysso_terrafssotesdev_1/exk1f7f7f7fk5wp50h8/sso/saml" + issuer_uri = "http://www.okta.com/exk1f716hf7f750h8" + request_binding = "HTTP-POST" + response_signature_algorithm = "SHA-256" +} diff --git a/examples/Federated-Settings/output.tf b/examples/Federated-Settings/output.tf new file mode 100644 index 0000000000..57fdd7f211 --- /dev/null +++ b/examples/Federated-Settings/output.tf @@ -0,0 +1,15 @@ +output "federated_settings_ds" { + value = data.mongodbatlas_federated_settings.federated_settings.id +} + +output "identity_provider" { + value = data.mongodbatlas_federated_settings_identity_providers.identity_provider.id +} + +output "org_configs_ds" { + value = data.mongodbatlas_federated_settings_org_configs.org_configs_ds.id +} + +output "org_role_mapping" { + value = data.mongodbatlas_federated_settings_org_role_mappings.org_role_mapping.id +} diff --git a/examples/Federated-Settings/provider.tf b/examples/Federated-Settings/provider.tf new file mode 100644 index 0000000000..18c430e061 --- /dev/null +++ b/examples/Federated-Settings/provider.tf @@ -0,0 +1,4 @@ +provider "mongodbatlas" { + public_key = var.public_key + private_key = var.private_key +} diff --git a/examples/Federated-Settings/variables.tf b/examples/Federated-Settings/variables.tf new file mode 100644 index 0000000000..003979e4fe --- /dev/null +++ b/examples/Federated-Settings/variables.tf @@ -0,0 +1,28 @@ +variable "public_key" { + type = string + description = "Public Programmatic API key to authenticate to Atlas" +} +variable "private_key" { + type = string + description = "Private Programmatic API key to authenticate to Atlas" +} +variable "org_id" { + type = string + description = "MongoDB Organization ID" +} +variable "group_id" { + type = string + description = "MongoDB Group ID" +} + +variable "name" { + type = string + description = "MongoDB Identity Provider Name" + default = "mongodb_federation_test" +} + +variable "identity_provider_id" { + type = string + description = "MongoDB Identity Provider ID" + default = "5754gdhgd758" +} diff --git a/examples/Federated-Settings/versions.tf b/examples/Federated-Settings/versions.tf new file mode 100644 index 0000000000..8d2a6743de --- /dev/null +++ b/examples/Federated-Settings/versions.tf @@ -0,0 +1,11 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + } + mongodbatlas = { + source = "mongodb/mongodbatlas" + } + } + required_version = ">= 0.13" +} diff --git a/examples/MongoDB-Atlas-Third-Party-Integration/.gitignore b/examples/MongoDB-Atlas-Third-Party-Integration/.gitignore new file mode 100644 index 0000000000..819a7c364a --- /dev/null +++ b/examples/MongoDB-Atlas-Third-Party-Integration/.gitignore @@ -0,0 +1,5 @@ +iatlaspl.code-workspace +terraform.tfvars +.terraform/ +*.tfstate* + diff --git a/examples/MongoDB-Atlas-Third-Party-Integration/Readme.md b/examples/MongoDB-Atlas-Third-Party-Integration/Readme.md new file mode 100644 index 0000000000..21bbfb4398 --- /dev/null +++ b/examples/MongoDB-Atlas-Third-Party-Integration/Readme.md @@ -0,0 +1,68 @@ +# Example - A basic example configuring MongoDB Atlas Third Party Integrations and Terraform + +This project aims to provide a very straight-forward example of setting up Terraform with MongoDB Atlas. This will create the following resources in MongoDB Atlas: + +- Atlas Project +- Microst Teams Third Party Integration +- Prometheus Third Party Integration + + +You can refer to the MongoDB Atlas documentation to know about the parameters that support Third Party Integrations. + +[Prometheus](https://www.mongodb.com/docs/atlas/tutorial/prometheus-integration/#std-label-httpsd-prometheus-config) + +[Microsoft Teams](https://www.mongodb.com/docs/atlas/tutorial/integrate-msft-teams/) + +## Dependencies + +* Terraform v0.13 or greater +* A MongoDB Atlas account +* provider.mongodbatlas: version = "~> 0.9.1" + +## Usage + +**1\. Ensure your MongoDB Atlas credentials are set up.** + +This can be done using environment variables: + +```bash +export MONGODB_ATLAS_PUBLIC_KEY="xxxx" +export MONGODB_ATLAS_PRIVATE_KEY="xxxx" +``` + +... or follow as in the `variables.tf` file and create **terraform.tfvars** file with all the variable values and make sure **not to commit it**. + + +> **IMPORTANT** Hard-coding your MongoDB Atlas programmatic API key pair into a Terraform configuration is not recommended. Consider the risks, especially the inadvertent submission of a configuration file containing secrets to a public repository. + + +**2\. Review the Terraform plan.** + +Execute the below command and ensure you are happy with the plan. + +``` bash +$ terraform plan +``` + +This project currently creates the below deployments: + +- Atlas Project +- Microst Teams Third Party Integration +- Prometheus Third Party Integration + +**3\. Execute the Terraform apply.** + +Now execute the plan to provision the MongoDB Atlas resources. + +``` bash +$ terraform apply +``` + +**4\. Destroy the resources.** + +Once you are finished your testing, ensure you destroy the resources to avoid unnecessary charges. + +``` bash +$ terraform destroy +``` + diff --git a/examples/MongoDB-Atlas-Third-Party-Integration/project.tf b/examples/MongoDB-Atlas-Third-Party-Integration/project.tf new file mode 100644 index 0000000000..30e0719097 --- /dev/null +++ b/examples/MongoDB-Atlas-Third-Party-Integration/project.tf @@ -0,0 +1,7 @@ +resource "mongodbatlas_project" "project" { + name = var.project_name + org_id = var.org_id +} +output "project_name" { + value = mongodbatlas_project.project.name +} diff --git a/examples/MongoDB-Atlas-Third-Party-Integration/provider.tf b/examples/MongoDB-Atlas-Third-Party-Integration/provider.tf new file mode 100644 index 0000000000..18c430e061 --- /dev/null +++ b/examples/MongoDB-Atlas-Third-Party-Integration/provider.tf @@ -0,0 +1,4 @@ +provider "mongodbatlas" { + public_key = var.public_key + private_key = var.private_key +} diff --git a/examples/MongoDB-Atlas-Third-Party-Integration/third-party-integration.tf b/examples/MongoDB-Atlas-Third-Party-Integration/third-party-integration.tf new file mode 100644 index 0000000000..5688208c28 --- /dev/null +++ b/examples/MongoDB-Atlas-Third-Party-Integration/third-party-integration.tf @@ -0,0 +1,15 @@ +resource "mongodbatlas_third_party_integration" "test_msteams" { + project_id = mongodbatlas_project.project.id + type = "MICROSOFT_TEAMS" + microsoft_teams_webhook_url = var.microsoft_teams_webhook_url +} + +resource "mongodbatlas_third_party_integration" "test_prometheus" { + project_id = mongodbatlas_project.project.id + type = "PROMETHEUS" + user_name = var.user_name + password = var.password + service_discovery = "file" + scheme = "https" + enabled = true +} diff --git a/examples/MongoDB-Atlas-Third-Party-Integration/variables.tf b/examples/MongoDB-Atlas-Third-Party-Integration/variables.tf new file mode 100644 index 0000000000..26c6d31da6 --- /dev/null +++ b/examples/MongoDB-Atlas-Third-Party-Integration/variables.tf @@ -0,0 +1,31 @@ +variable "public_key" { + type = string + description = "Public Programmatic API key to authenticate to Atlas" +} +variable "private_key" { + type = string + description = "Private Programmatic API key to authenticate to Atlas" +} +variable "org_id" { + type = string + description = "MongoDB Organization ID" +} +variable "project_name" { + type = string + description = "The MongoDB Atlas Project Name" +} +variable "user_name" { + type = string + description = "The Prometheus User Name" + default = "puser" +} +variable "password" { + type = string + description = "The Prometheus Password" + default = "ppassword" +} +variable "microsoft_teams_webhook_url" { + type = string + description = "The Microsoft Teams Webhook URL" + default = "https://yourcompany.webhook.office.com/webhookb2/zzz@yyy/IncomingWebhook/xyz" +} diff --git a/examples/MongoDB-Atlas-Third-Party-Integration/versions.tf b/examples/MongoDB-Atlas-Third-Party-Integration/versions.tf new file mode 100644 index 0000000000..d55e59c63d --- /dev/null +++ b/examples/MongoDB-Atlas-Third-Party-Integration/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + mongodbatlas = { + source = "mongodb/mongodbatlas" + } + } + required_version = ">= 0.13" +} diff --git a/examples/aws-atlas-privatelink-regionalized/Readme.md b/examples/aws-atlas-privatelink-regionalized/Readme.md new file mode 100644 index 0000000000..2bf81acb17 --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/Readme.md @@ -0,0 +1,112 @@ +# Example - AWS and Atlas PrivateLink Regionalized Mode with Terraform + +This project aims to provide a very straight-forward example of setting up PrivateLink connection between AWS and MongoDB Atlas. Using `mongodbatlas_private_endpoint_regional_mode` to determine if it's enabled or not. + +## Gotchas +- Ensure `mongodbatlas_cluster` depends_on `mongodbatlas_private_endpoint_regional_mode` +- Despite being properly output, connection strings _may not be applied_ to `mongodbatlas_cluster` resource when changing regional mode enabled. This means the connection_strings may not exist in terraform state until the next `terraform apply`. + +## Dependencies + +* Terraform v0.13 +* An AWS account - provider.aws: version = "~> 3.3" +* A MongoDB Atlas account - provider.mongodbatlas: version = "~> 0.6" + +## Usage + +**1\. Ensure your AWS and MongoDB Atlas credentials are set up.** + +This can be done using environment variables: + +``` bash +$ export AWS_SECRET_ACCESS_KEY='your secret key' +$ export AWS_ACCESS_KEY_ID='your key id' +``` + +```bash +export MONGODB_ATLAS_PUBLIC_KEY="xxxx" +export MONGODB_ATLAS_PRIVATE_KEY="xxxx" +``` + +... or the `~/.aws/credentials` file. + +``` +$ cat ~/.aws/credentials +[default] +aws_access_key_id = your key id +aws_secret_access_key = your secret key + +``` +... or follow as in the `variables.tf` file and create **terraform.tfvars** file with all the variable values and make sure **not to commit it**. + +**2\. Review the Terraform plan.** + +Execute the below command and ensure you are happy with the plan. + +``` bash +$ terraform plan +``` +This project currently does the below deployments: + +- MongoDB cluster - M10 +- AWS Custom VPC, Internet Gateway, Route Tables, Subnets with Public and Private access +- PrivateLink Connection at MongoDB Atlas +- Create VPC Endpoint in AWS + +**3\. Configure the security group as required.** + +The security group in this configuration allows All Traffic access in Inbound and Outbound Rules. + +**4\. Execute the Terraform apply.** + +Now execute the plan to provision the AWS and Atlas resources. + +``` bash +$ terraform apply +``` + +**5\. Destroy the resources.** + +Once you are finished your testing, ensure you destroy the resources to avoid unnecessary charges. + +``` bash +$ terraform destroy +``` + +**Important Point** + +To fetch the connection string follow the below steps: +``` +output "atlasclusterstring" { + value = mongodbatlas_cluster.cluster-atlas.connection_strings +} +``` +**Outputs:** +``` +atlasclusterstring = [ + { + "aws_private_link" = { + "vpce-0ebb76559e8affc96" = "mongodb://pl-0-us-east-1.za3fb.mongodb.net:1024,pl-0-us-east-1.za3fb.mongodb.net:1025,pl-0-us-east-1.za3fb.mongodb.net:1026/?ssl=true&authSource=admin&replicaSet=atlas-d177ke-shard-0" + } + "aws_private_link_srv" = { + "vpce-0ebb76559e8affc96" = "mongodb+srv://cluster-atlas-pl-0.za3fb.mongodb.net" + } + "private" = "" + "private_srv" = "" + "standard" = "mongodb://cluster-atlas-shard-00-00.za3fb.mongodb.net:27017,cluster-atlas-shard-00-01.za3fb.mongodb.net:27017,cluster-atlas-shard-00-02.za3fb.mongodb.net:27017/?ssl=true&authSource=admin&replicaSet=atlas-d177ke-shard-0" + "standard_srv" = "mongodb+srv://cluster-atlas.za3fb.mongodb.net" + }, +] +``` + +To fetch a particular connection string, use the **lookup()** function of terraform as below: + +``` +output "plstring" { + value = lookup(mongodbatlas_cluster.cluster-atlas.connection_strings[0].aws_private_link_srv, aws_vpc_endpoint.ptfe_service.id) +} +``` +**Output:** +``` +plstring = mongodb+srv://cluster-atlas-pl-0.za3fb.mongodb.net +``` diff --git a/examples/aws-atlas-privatelink-regionalized/atlas-cluster.tf b/examples/aws-atlas-privatelink-regionalized/atlas-cluster.tf new file mode 100644 index 0000000000..e7e49662e4 --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/atlas-cluster.tf @@ -0,0 +1,47 @@ +resource "mongodbatlas_cluster" "cluster-atlas" { + project_id = var.atlasprojectid + name = "cluster-atlas" + cloud_backup = true + auto_scaling_disk_gb_enabled = true + mongo_db_major_version = "5.0" + cluster_type = "GEOSHARDED" + replication_specs { + zone_name = "Zone 1" + num_shards = 2 + regions_config { + region_name = var.atlas_region_east + electable_nodes = 3 + priority = 7 + read_only_nodes = 0 + } + } + + replication_specs { + zone_name = "Zone 2" + num_shards = 2 + regions_config { + region_name = var.atlas_region_west + electable_nodes = 3 + priority = 7 + read_only_nodes = 0 + } + } + # Provider settings + provider_name = "AWS" + disk_size_gb = 80 + provider_instance_size_name = "M30" +} + +data "mongodbatlas_cluster" "cluster-atlas" { + project_id = var.atlasprojectid + name = mongodbatlas_cluster.cluster-atlas.name + depends_on = [ + mongodbatlas_privatelink_endpoint_service.atlaseplink_east, + mongodbatlas_privatelink_endpoint_service.atlaseplink_west, + mongodbatlas_private_endpoint_regional_mode.test + ] +} + +output "atlasclusterstring" { + value = data.mongodbatlas_cluster.cluster-atlas.connection_strings +} diff --git a/examples/aws-atlas-privatelink-regionalized/atlas-pl.tf b/examples/aws-atlas-privatelink-regionalized/atlas-pl.tf new file mode 100644 index 0000000000..a8639f9182 --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/atlas-pl.tf @@ -0,0 +1,47 @@ +resource "mongodbatlas_private_endpoint_regional_mode" "test" { + project_id = var.atlasprojectid + enabled = true +} + +resource "mongodbatlas_privatelink_endpoint" "atlaspl_east" { + project_id = var.atlasprojectid + provider_name = "AWS" + region = var.aws_region_east +} + +resource "mongodbatlas_privatelink_endpoint" "atlaspl_west" { + project_id = var.atlasprojectid + provider_name = "AWS" + region = var.aws_region_west +} + +resource "aws_vpc_endpoint" "ptfe_service_west" { + provider = aws.west + vpc_id = aws_vpc.west.id + service_name = mongodbatlas_privatelink_endpoint.atlaspl_west.endpoint_service_name + vpc_endpoint_type = "Interface" + subnet_ids = [aws_subnet.west.id] + security_group_ids = [aws_security_group.west.id] +} + +resource "aws_vpc_endpoint" "ptfe_service_east" { + vpc_id = aws_vpc.primary.id + service_name = mongodbatlas_privatelink_endpoint.atlaspl_east.endpoint_service_name + vpc_endpoint_type = "Interface" + subnet_ids = [aws_subnet.primary.id] + security_group_ids = [aws_security_group.primary_default.id] +} + +resource "mongodbatlas_privatelink_endpoint_service" "atlaseplink_west" { + project_id = mongodbatlas_privatelink_endpoint.atlaspl_west.project_id + endpoint_service_id = aws_vpc_endpoint.ptfe_service_west.id + private_link_id = mongodbatlas_privatelink_endpoint.atlaspl_west.id + provider_name = "AWS" +} + +resource "mongodbatlas_privatelink_endpoint_service" "atlaseplink_east" { + project_id = mongodbatlas_privatelink_endpoint.atlaspl_east.project_id + endpoint_service_id = aws_vpc_endpoint.ptfe_service_east.id + private_link_id = mongodbatlas_privatelink_endpoint.atlaspl_east.id + provider_name = "AWS" +} diff --git a/examples/aws-atlas-privatelink-regionalized/aws-east-vpc.tf b/examples/aws-atlas-privatelink-regionalized/aws-east-vpc.tf new file mode 100644 index 0000000000..d0b92f47f8 --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/aws-east-vpc.tf @@ -0,0 +1,51 @@ +# Create Primary VPC +resource "aws_vpc" "primary" { + cidr_block = "10.0.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true +} + +# Create IGW +resource "aws_internet_gateway" "primary" { + vpc_id = aws_vpc.primary.id +} + +# Route Table +resource "aws_route" "primary-internet_access" { + route_table_id = aws_vpc.primary.main_route_table_id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.primary.id +} + +# Subnet-A +resource "aws_subnet" "primary" { + vpc_id = aws_vpc.primary.id + cidr_block = "10.0.2.0/24" + map_public_ip_on_launch = true + availability_zone = "${var.aws_region_east}a" +} + +/*Security-Group +Ingress - Port 80 -- limited to instance + Port 22 -- Open to ssh without limitations +Egress - Open to All*/ + +resource "aws_security_group" "primary_default" { + name_prefix = "default-" + description = "Default security group for all instances in ${aws_vpc.primary.id}" + vpc_id = aws_vpc.primary.id + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = [ + aws_vpc.primary.cidr_block, + ] + } + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} diff --git a/examples/aws-atlas-privatelink-regionalized/aws-west-vpc.tf b/examples/aws-atlas-privatelink-regionalized/aws-west-vpc.tf new file mode 100644 index 0000000000..87783963cc --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/aws-west-vpc.tf @@ -0,0 +1,56 @@ +# Create Primary VPC +resource "aws_vpc" "west" { + provider = aws.west + cidr_block = "10.0.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true +} + +# Create IGW +resource "aws_internet_gateway" "west" { + provider = aws.west + vpc_id = aws_vpc.west.id +} + +# Route Table +resource "aws_route" "west-internet_access" { + provider = aws.west + route_table_id = aws_vpc.west.main_route_table_id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.west.id +} + +# Subnet-B +resource "aws_subnet" "west" { + provider = aws.west + vpc_id = aws_vpc.west.id + cidr_block = "10.0.1.0/24" + map_public_ip_on_launch = true + availability_zone = "${var.aws_region_west}b" +} + +/*Security-Group +Ingress - Port 80 -- limited to instance + Port 22 -- Open to ssh without limitations +Egress - Open to All*/ + +resource "aws_security_group" "west" { + provider = aws.west + name_prefix = "default-" + description = "Default security group for all instances in ${aws_vpc.west.id}" + vpc_id = aws_vpc.west.id + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = [ + aws_vpc.primary.cidr_block, + ] + } + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} diff --git a/examples/aws-atlas-privatelink-regionalized/provider.tf b/examples/aws-atlas-privatelink-regionalized/provider.tf new file mode 100644 index 0000000000..810d0a1f6f --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/provider.tf @@ -0,0 +1,15 @@ +provider "mongodbatlas" { + public_key = var.public_key + private_key = var.private_key +} +provider "aws" { + access_key = var.access_key + secret_key = var.secret_key + region = var.aws_region_east +} +provider "aws" { + alias = "west" + access_key = var.access_key + secret_key = var.secret_key + region = var.aws_region_west +} diff --git a/examples/aws-atlas-privatelink-regionalized/variables.tf b/examples/aws-atlas-privatelink-regionalized/variables.tf new file mode 100644 index 0000000000..91076e4569 --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/variables.tf @@ -0,0 +1,32 @@ +variable "public_key" { + description = "The public API key for MongoDB Atlas" +} +variable "private_key" { + description = "The private API key for MongoDB Atlas" +} +variable "atlasprojectid" { + description = "Atlas project ID" +} +variable "access_key" { + description = "The access key for AWS Account" +} +variable "secret_key" { + description = "The secret key for AWS Account" +} +variable "atlas_region_east" { + default = "US_EAST_1" + description = "Atlas Region East" +} +variable "atlas_region_west" { + default = "US_WEST_1" + description = "Atlas Region West" +} +variable "aws_region_east" { + default = "us-east-1" + description = "AWS Region East" +} + +variable "aws_region_west" { + default = "us-west-1" + description = "AWS Region West" +} diff --git a/examples/aws-atlas-privatelink-regionalized/versions.tf b/examples/aws-atlas-privatelink-regionalized/versions.tf new file mode 100644 index 0000000000..5584f665d2 --- /dev/null +++ b/examples/aws-atlas-privatelink-regionalized/versions.tf @@ -0,0 +1,11 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + mongodbatlas = { + source = "mongodb/mongodbatlas" + } + } + required_version = ">= 0.13" +} diff --git a/go.mod b/go.mod index 022a55437d..05cade294d 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,6 @@ require ( github.com/mwielbut/pointy v1.1.0 github.com/spf13/cast v1.5.0 github.com/terraform-providers/terraform-provider-aws v1.60.1-0.20210625132053-af2d5c0ad54f - go.mongodb.org/atlas v0.15.1-0.20220215171307-4b760c3c624f + go.mongodb.org/atlas v0.16.1-0.20220531163122-551edbfb2f27 go.mongodb.org/realm v0.1.0 ) diff --git a/go.sum b/go.sum index 24e0498025..72303a03a3 100644 --- a/go.sum +++ b/go.sum @@ -1230,8 +1230,8 @@ go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQc go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.mongodb.org/atlas v0.12.0/go.mod h1:wVCnHcm/7/IfTjEB6K8K35PLG70yGz8BdkRwX0oK9/M= -go.mongodb.org/atlas v0.15.1-0.20220215171307-4b760c3c624f h1:IvKkFdSSBLC5kqB1X87vn8CRAI7eXoMSK7u2lG+WUg8= -go.mongodb.org/atlas v0.15.1-0.20220215171307-4b760c3c624f/go.mod h1:lQhRHIxc6jQHEK3/q9WLu/SdBkPj2fQYhjLGUF6Z3U8= +go.mongodb.org/atlas v0.16.1-0.20220531163122-551edbfb2f27 h1:rGTb8CaE9ZKNjmdUJ58jFcHopLg6o6Kzfm9AIayq1Hw= +go.mongodb.org/atlas v0.16.1-0.20220531163122-551edbfb2f27/go.mod h1:lQhRHIxc6jQHEK3/q9WLu/SdBkPj2fQYhjLGUF6Z3U8= go.mongodb.org/realm v0.1.0 h1:zJiXyLaZrznQ+Pz947ziSrDKUep39DO4SfA0Fzx8M4M= go.mongodb.org/realm v0.1.0/go.mod h1:4Vj6iy+Puo1TDERcoh4XZ+pjtwbOzPpzqy3Cwe8ZmDM= go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= diff --git a/mongodbatlas/data_source_mongodbatlas_cloud_backup_schedule.go b/mongodbatlas/data_source_mongodbatlas_cloud_backup_schedule.go index 9c6a555f23..f26040c95b 100644 --- a/mongodbatlas/data_source_mongodbatlas_cloud_backup_schedule.go +++ b/mongodbatlas/data_source_mongodbatlas_cloud_backup_schedule.go @@ -45,6 +45,30 @@ func dataSourceMongoDBAtlasCloudBackupSchedule() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "auto_export_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "use_org_and_group_names_in_export_prefix": { + Type: schema.TypeBool, + Computed: true, + }, + "export": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "export_bucket_id": { + Type: schema.TypeString, + Computed: true, + }, + "frequency_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "policy_item_hourly": { Type: schema.TypeList, Computed: true, @@ -193,11 +217,18 @@ func dataSourceMongoDBAtlasCloudBackupScheduleRead(ctx context.Context, d *schem if err := d.Set("next_snapshot", backupPolicy.NextSnapshot); err != nil { return diag.Errorf(errorSnapshotBackupScheduleSetting, "next_snapshot", clusterName, err) } - + if err := d.Set("use_org_and_group_names_in_export_prefix", backupPolicy.UseOrgAndGroupNamesInExportPrefix); err != nil { + return diag.Errorf(errorSnapshotBackupScheduleSetting, "use_org_and_group_names_in_export_prefix", clusterName, err) + } + if err := d.Set("auto_export_enabled", backupPolicy.AutoExportEnabled); err != nil { + return diag.Errorf(errorSnapshotBackupScheduleSetting, "auto_export_enabled", clusterName, err) + } if err := d.Set("id_policy", backupPolicy.Policies[0].ID); err != nil { return diag.Errorf(errorSnapshotBackupScheduleSetting, "id_policy", clusterName, err) } - + if err := d.Set("export", flattenExport(backupPolicy)); err != nil { + return diag.Errorf(errorSnapshotBackupScheduleSetting, "auto_export_enabled", clusterName, err) + } if err := d.Set("policy_item_hourly", flattenPolicyItem(backupPolicy.Policies[0].PolicyItems, snapshotScheduleHourly)); err != nil { return diag.Errorf(errorSnapshotBackupScheduleSetting, "policy_item_hourly", clusterName, err) } @@ -214,6 +245,9 @@ func dataSourceMongoDBAtlasCloudBackupScheduleRead(ctx context.Context, d *schem return diag.Errorf(errorSnapshotBackupScheduleSetting, "policy_item_monthly", clusterName, err) } + if err := d.Set("export", flattenExport(backupPolicy)); err != nil { + return diag.Errorf(errorSnapshotBackupScheduleSetting, "export", clusterName, err) + } d.SetId(encodeStateID(map[string]string{ "project_id": projectID, "cluster_name": clusterName, diff --git a/mongodbatlas/data_source_mongodbatlas_cloud_provider_access.go b/mongodbatlas/data_source_mongodbatlas_cloud_provider_access.go index 2bcfd65f3b..1f18e51062 100644 --- a/mongodbatlas/data_source_mongodbatlas_cloud_provider_access.go +++ b/mongodbatlas/data_source_mongodbatlas_cloud_provider_access.go @@ -144,3 +144,18 @@ func featureToSchema(feature *matlas.FeatureUsage) map[string]interface{} { "feature_id": feature.FeatureID, } } + +func featureUsagesSchemaV0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "feature_type": { + Type: schema.TypeString, + Computed: true, + }, + "feature_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} diff --git a/mongodbatlas/data_source_mongodbatlas_event_trigger.go b/mongodbatlas/data_source_mongodbatlas_event_trigger.go index 4930788722..9c342ccf35 100644 --- a/mongodbatlas/data_source_mongodbatlas_event_trigger.go +++ b/mongodbatlas/data_source_mongodbatlas_event_trigger.go @@ -122,6 +122,10 @@ func dataSourceMongoDBAtlasEventTrigger() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "unordered": { + Type: schema.TypeBool, + Computed: true, + }, }, } } @@ -191,6 +195,9 @@ func dataSourceMongoDBAtlasEventTriggerRead(ctx context.Context, d *schema.Resou if err = d.Set("config_schedule_type", eventResp.Config.ScheduleType); err != nil { return diag.FromErr(fmt.Errorf(errorEventTriggersSetting, "config_schedule_type", projectID, appID, err)) } + if err = d.Set("unordered", eventResp.Config.Unordered); err != nil { + return diag.FromErr(fmt.Errorf(errorEventTriggersSetting, "unordered", projectID, appID, err)) + } if err = d.Set("event_processors", flattenTriggerEventProcessorAWSEventBridge(eventResp.EventProcessors)); err != nil { return diag.FromErr(fmt.Errorf(errorEventTriggersSetting, "event_processors", projectID, appID, err)) } diff --git a/mongodbatlas/data_source_mongodbatlas_event_trigger_test.go b/mongodbatlas/data_source_mongodbatlas_event_trigger_test.go index 555bb5f3af..dadaedaebf 100644 --- a/mongodbatlas/data_source_mongodbatlas_event_trigger_test.go +++ b/mongodbatlas/data_source_mongodbatlas_event_trigger_test.go @@ -31,6 +31,7 @@ func TestAccDataSourceMongoDBAtlasEventTrigger_basic(t *testing.T) { Collection: "listingsAndReviews", ServiceID: os.Getenv("MONGODB_REALM_SERVICE_ID"), FullDocument: pointy.Bool(false), + Unordered: pointy.Bool(true), }, } @@ -58,6 +59,7 @@ func testAccMongoDBAtlasDataSourceEventTriggerConfig(projectID, appID, operation type = %[4]q function_id = %[5]q disabled = %[6]t + unordered = %[7]t config_operation_types = [%s] config_database = %[8]q config_collection = %[9]q @@ -70,7 +72,7 @@ func testAccMongoDBAtlasDataSourceEventTriggerConfig(projectID, appID, operation app_id = mongodbatlas_event_trigger.test.app_id trigger_id = mongodbatlas_event_trigger.test.id } -`, projectID, appID, eventTrigger.Name, eventTrigger.Type, eventTrigger.FunctionID, *eventTrigger.Disabled, operationTypes, +`, projectID, appID, eventTrigger.Name, eventTrigger.Type, eventTrigger.FunctionID, *eventTrigger.Disabled, *eventTrigger.Config.Unordered, operationTypes, eventTrigger.Config.Database, eventTrigger.Config.Collection, eventTrigger.Config.ServiceID) } diff --git a/mongodbatlas/data_source_mongodbatlas_event_triggers.go b/mongodbatlas/data_source_mongodbatlas_event_triggers.go index 35c62c1103..302b2fc5bc 100644 --- a/mongodbatlas/data_source_mongodbatlas_event_triggers.go +++ b/mongodbatlas/data_source_mongodbatlas_event_triggers.go @@ -131,6 +131,10 @@ func dataSourceMongoDBAtlasEventTriggers() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "unordered": { + Type: schema.TypeBool, + Computed: true, + }, }, }, }, @@ -190,6 +194,7 @@ func flattenEventTriggers(eventTriggers []realm.EventTrigger) []map[string]inter "config_schedule": eventTriggers[i].Config.Schedule, "config_schedule_type": eventTriggers[i].Config.ScheduleType, "event_processors": flattenTriggerEventProcessorAWSEventBridge(eventTriggers[i].EventProcessors), + "unordered": eventTriggers[i].Config.Unordered, } } } diff --git a/mongodbatlas/data_source_mongodbatlas_event_triggers_test.go b/mongodbatlas/data_source_mongodbatlas_event_triggers_test.go index 310378aa85..4f56a5f008 100644 --- a/mongodbatlas/data_source_mongodbatlas_event_triggers_test.go +++ b/mongodbatlas/data_source_mongodbatlas_event_triggers_test.go @@ -33,6 +33,7 @@ func TestAccDataSourceMongoDBAtlasEventTriggers_basic(t *testing.T) { ServiceID: os.Getenv("MONGODB_REALM_SERVICE_ID"), FullDocument: pointy.Bool(false), Schedule: "*", + Unordered: pointy.Bool(true), }, } @@ -59,6 +60,7 @@ func testAccMongoDBAtlasEventTriggersDataSourceConfig(projectID, appID, operatio type = %[4]q function_id = %[5]q disabled = %[6]t + unordered = %[7]t config_operation_types = [%s] config_database = %[8]q config_collection = %[9]q @@ -70,7 +72,7 @@ func testAccMongoDBAtlasEventTriggersDataSourceConfig(projectID, appID, operatio project_id = mongodbatlas_event_trigger.test.project_id app_id = mongodbatlas_event_trigger.test.app_id } -`, projectID, appID, eventTrigger.Name, eventTrigger.Type, eventTrigger.FunctionID, *eventTrigger.Disabled, operationTypes, +`, projectID, appID, eventTrigger.Name, eventTrigger.Type, eventTrigger.FunctionID, *eventTrigger.Disabled, *eventTrigger.Config.Unordered, operationTypes, eventTrigger.Config.Database, eventTrigger.Config.Collection, eventTrigger.Config.ServiceID) } diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings.go b/mongodbatlas/data_source_mongodbatlas_federated_settings.go new file mode 100644 index 0000000000..305ca71d24 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings.go @@ -0,0 +1,99 @@ +package mongodbatlas + +import ( + "context" + "errors" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func dataSourceMongoDBAtlasFederatedSettings() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasFederatedSettingsRead, + Schema: map[string]*schema.Schema{ + "org_id": { + Type: schema.TypeString, + Required: true, + }, + "federated_domains": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "has_role_mappings": { + Type: schema.TypeBool, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "identity_provider_id": { + Type: schema.TypeString, + Computed: true, + }, + "identity_provider_status": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceMongoDBAtlasFederatedSettingsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + orgID, orgIDOk := d.GetOk("org_id") + + if !orgIDOk { + return diag.FromErr(errors.New("org_id must be configured")) + } + + var ( + err error + org *matlas.Organization + ) + + if orgIDOk { + org, _, err = conn.Organizations.Get(ctx, orgID.(string)) + } + + if err != nil { + return diag.Errorf("Error reading Organization %s %s", orgID, err) + } + + federationSettings, _, err := conn.FederatedSettings.Get(ctx, org.ID) + if err != nil { + return diag.Errorf("error getting Federated settings (%s): %s", orgID, err) + } + + if err := d.Set("org_id", org.ID); err != nil { + return diag.Errorf("error getting Federated settings (%s): %s %s", `org_id`, org.ID, err) + } + + if err := d.Set("federated_domains", federationSettings.FederatedDomains); err != nil { + return diag.Errorf("error getting Federated settings (%s): %s %s", `federated_domains`, federationSettings.FederatedDomains, err) + } + + if err := d.Set("identity_provider_status", federationSettings.IdentityProviderStatus); err != nil { + return diag.Errorf("error getting Federated settings (%s): %s %s", `identityProviderStatus`, federationSettings.IdentityProviderStatus, err) + } + + if err := d.Set("identity_provider_id", federationSettings.IdentityProviderID); err != nil { + return diag.Errorf("error getting Federated settings (%s): %s %s", `IdentityProviderID`, federationSettings.IdentityProviderID, err) + } + + if err := d.Set("has_role_mappings", federationSettings.HasRoleMappings); err != nil { + return diag.Errorf("error getting Federated settings (%s): flag %s ", `HasRoleMappings`, err) + } + + d.SetId(federationSettings.ID) + + return nil +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organization.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organization.go new file mode 100644 index 0000000000..963a50e196 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organization.go @@ -0,0 +1,170 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceMongoDBAtlasFederatedSettingsOrganizationConfig() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasFederatedSettingsOrganizationConfigRead, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "org_id": { + Type: schema.TypeString, + Required: true, + }, + "domain_allow_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "domain_restriction_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "identity_provider_id": { + Type: schema.TypeString, + Computed: true, + }, + "post_auth_role_grants": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "role_mappings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "external_group_name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "role_assignments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "role": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "user_conflicts": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "email_address": { + Type: schema.TypeString, + Computed: true, + }, + "federation_settings_id": { + Type: schema.TypeString, + Computed: true, + }, + "first_name": { + Type: schema.TypeString, + Computed: true, + }, + "last_name": { + Type: schema.TypeString, + Computed: true, + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} +func dataSourceMongoDBAtlasFederatedSettingsOrganizationConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + federationSettingsID, federationSettingsIDOk := d.GetOk("federation_settings_id") + + if !federationSettingsIDOk { + return diag.FromErr(errors.New("federation_settings_id must be configured")) + } + + orgID, orgIDOk := d.GetOk("org_id") + + if !orgIDOk { + return diag.FromErr(errors.New("org_id must be configured")) + } + + federatedSettingsConnectedOrganization, _, err := conn.FederatedSettings.GetConnectedOrg(ctx, federationSettingsID.(string), orgID.(string)) + if err != nil { + return diag.Errorf("error getting federatedSettings connected organizations assigned (%s): %s", federationSettingsID, err) + } + + if err := d.Set("domain_allow_list", federatedSettingsConnectedOrganization.DomainAllowList); err != nil { + return diag.FromErr(fmt.Errorf("error setting `domain_allow_list` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("domain_restriction_enabled", federatedSettingsConnectedOrganization.DomainRestrictionEnabled); err != nil { + return diag.FromErr(fmt.Errorf("error setting `domain_restriction_enabled` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("identity_provider_id", federatedSettingsConnectedOrganization.IdentityProviderID); err != nil { + return diag.FromErr(fmt.Errorf("error setting `identity_provider_id` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("org_id", federatedSettingsConnectedOrganization.OrgID); err != nil { + return diag.FromErr(fmt.Errorf("error setting `org_id` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("post_auth_role_grants", federatedSettingsConnectedOrganization.PostAuthRoleGrants); err != nil { + return diag.FromErr(fmt.Errorf("error setting `post_auth_role_grants` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("role_mappings", flattenRoleMappings(federatedSettingsConnectedOrganization.RoleMappings)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `role_mappings` for federatedSettings IdentityProviders: %s", err)) + } + if federatedSettingsConnectedOrganization.UserConflicts == nil { + if err := d.Set("user_conflicts", federatedSettingsConnectedOrganization.UserConflicts); err != nil { + return diag.FromErr(fmt.Errorf("error setting `user_conflicts` for federatedSettings IdentityProviders: %s", err)) + } + } else { + if err := d.Set("user_conflicts", flattenUserConflicts(*federatedSettingsConnectedOrganization.UserConflicts)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `user_conflicts` for federatedSettings IdentityProviders: %s", err)) + } + } + + d.SetId(federatedSettingsConnectedOrganization.OrgID) + + return nil +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organization_test.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organization_test.go new file mode 100644 index 0000000000..2fe561d70f --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organization_test.go @@ -0,0 +1,70 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceMongoDBAtlasFederatedSettingsOrganizationConfig_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "data.mongodbatlas_federated_settings_org_config.test" + federatedSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationConfigConfig(federatedSettingsID, orgID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "federation_settings_id"), + resource.TestCheckResourceAttrSet(resourceName, "role_mappings.#"), + resource.TestCheckResourceAttrSet(resourceName, "identity_provider_id"), + resource.TestCheckResourceAttrSet(resourceName, "org_id"), + resource.TestCheckResourceAttr(resourceName, "identity_provider_id", "0oad4fas87jL5Xnk1297"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationConfigConfig(federatedSettingsID, orgID string) string { + return fmt.Sprintf(` + data "mongodbatlas_federated_settings_org_config" "test" { + federation_settings_id = "%[1]s" + org_id = "%[2]s" + + } +`, federatedSettingsID, orgID) +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + _, _, err := conn.FederatedSettings.ListConnectedOrgs(context.Background(), rs.Primary.Attributes["federation_settings_id"], nil) + if err != nil { + return fmt.Errorf("FederatedSettingsConnectedOrganization (%s) does not exist", rs.Primary.ID) + } + + return nil + } +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organizations.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organizations.go new file mode 100644 index 0000000000..affd59fd73 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organizations.go @@ -0,0 +1,191 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func dataSourceMongoDBAtlasFederatedSettingsOrganizationConfigs() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasFederatedSettingsOrganizationConfigsRead, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "page_num": { + Type: schema.TypeInt, + Optional: true, + }, + "items_per_page": { + Type: schema.TypeInt, + Optional: true, + }, + "results": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "domain_allow_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "domain_restriction_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "identity_provider_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "post_auth_role_grants": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "role_mappings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "external_group_name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "role_assignments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "role": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "user_conflicts": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "email_address": { + Type: schema.TypeString, + Computed: true, + }, + "federation_settings_id": { + Type: schema.TypeString, + Computed: true, + }, + "first_name": { + Type: schema.TypeString, + Computed: true, + }, + "last_name": { + Type: schema.TypeString, + Computed: true, + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} +func dataSourceMongoDBAtlasFederatedSettingsOrganizationConfigsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + federationSettingsID, federationSettingsIDOk := d.GetOk("federation_settings_id") + + options := &matlas.ListOptions{ + PageNum: d.Get("page_num").(int), + ItemsPerPage: d.Get("items_per_page").(int), + } + + if !federationSettingsIDOk { + return diag.FromErr(errors.New("either federation_settings_id must be configured")) + } + + federatedSettingsConnectedOrganizations, _, err := conn.FederatedSettings.ListConnectedOrgs(ctx, federationSettingsID.(string), options) + if err != nil { + return diag.Errorf("error getting federatedSettings connected organizations assigned (%s): %s", federationSettingsID, err) + } + + if err := d.Set("results", flattenFederatedSettingsOrganizationConfigs(*federatedSettingsConnectedOrganizations)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `result` for federatedSettings IdentityProviders: %s", err)) + } + + d.SetId(federationSettingsID.(string)) + + return nil +} + +func flattenFederatedSettingsOrganizationConfigs(federatedSettingsConnectedOrganizations matlas.FederatedSettingsConnectedOrganizations) []map[string]interface{} { + var federatedSettingsConnectedOrganizationsMap []map[string]interface{} + + if (federatedSettingsConnectedOrganizations.TotalCount) > 0 { + federatedSettingsConnectedOrganizationsMap = make([]map[string]interface{}, federatedSettingsConnectedOrganizations.TotalCount) + + for i := range federatedSettingsConnectedOrganizations.Results { + if federatedSettingsConnectedOrganizations.Results[i].UserConflicts == nil { + federatedSettingsConnectedOrganizationsMap[i] = map[string]interface{}{ + "domain_allow_list": federatedSettingsConnectedOrganizations.Results[i].DomainAllowList, + "domain_restriction_enabled": federatedSettingsConnectedOrganizations.Results[i].DomainRestrictionEnabled, + "identity_provider_id": federatedSettingsConnectedOrganizations.Results[i].IdentityProviderID, + "org_id": federatedSettingsConnectedOrganizations.Results[i].OrgID, + "post_auth_role_grants": federatedSettingsConnectedOrganizations.Results[i].PostAuthRoleGrants, + "role_mappings": flattenRoleMappings(federatedSettingsConnectedOrganizations.Results[i].RoleMappings), + "user_conflicts": nil, + } + } else { + federatedSettingsConnectedOrganizationsMap[i] = map[string]interface{}{ + "domain_allow_list": federatedSettingsConnectedOrganizations.Results[i].DomainAllowList, + "domain_restriction_enabled": federatedSettingsConnectedOrganizations.Results[i].DomainRestrictionEnabled, + "identity_provider_id": federatedSettingsConnectedOrganizations.Results[i].IdentityProviderID, + "org_id": federatedSettingsConnectedOrganizations.Results[i].OrgID, + "post_auth_role_grants": federatedSettingsConnectedOrganizations.Results[i].PostAuthRoleGrants, + "role_mappings": flattenRoleMappings(federatedSettingsConnectedOrganizations.Results[i].RoleMappings), + "user_conflicts": flattenUserConflicts(*federatedSettingsConnectedOrganizations.Results[i].UserConflicts), + } + } + } + } + + return federatedSettingsConnectedOrganizationsMap +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organizations_test.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organizations_test.go new file mode 100644 index 0000000000..6a1fc8913e --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_connected_organizations_test.go @@ -0,0 +1,69 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceMongoDBAtlasFederatedSettingsOrganizationConfigs_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "data.mongodbatlas_federated_settings_org_configs.test" + federatedSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationConfigsConfig(federatedSettingsID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigsExists(resourceName), + + resource.TestCheckResourceAttrSet(resourceName, "federation_settings_id"), + resource.TestCheckResourceAttrSet(resourceName, "results.#"), + resource.TestCheckResourceAttrSet(resourceName, "results.0.identity_provider_id"), + resource.TestCheckResourceAttrSet(resourceName, "results.0.org_id"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationConfigsConfig(federatedSettingsID string) string { + return fmt.Sprintf(` + data "mongodbatlas_federated_settings_org_configs" "test" { + federation_settings_id = "%[1]s" + page_num = 1 + items_per_page = 100 + } +`, federatedSettingsID) +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigsExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + _, _, err := conn.FederatedSettings.ListConnectedOrgs(context.Background(), rs.Primary.Attributes["federation_settings_id"], nil) + if err != nil { + return fmt.Errorf("FederatedSettingsConnectedOrganization (%s) does not exist", rs.Primary.ID) + } + + return nil + } +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_provider.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_provider.go new file mode 100644 index 0000000000..9a1954b00f --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_provider.go @@ -0,0 +1,273 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceMongoDBAtlasFederatedSettingsIdentityProvider() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasFederatedSettingsIdentityProviderRead, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "identity_provider_id": { + Type: schema.TypeString, + Required: true, + }, + + "acs_url": { + Type: schema.TypeString, + Computed: true, + }, + "associated_domains": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "associated_orgs": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "domain_allow_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "domain_restriction_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "identity_provider_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "post_auth_role_grants": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "role_mappings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "external_group_name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "role_assignments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "role": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "user_conflicts": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "email_address": { + Type: schema.TypeString, + Computed: true, + }, + "federation_settings_id": { + Type: schema.TypeString, + Computed: true, + }, + "first_name": { + Type: schema.TypeString, + Computed: true, + }, + "last_name": { + Type: schema.TypeString, + Computed: true, + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "audience_uri": { + Type: schema.TypeString, + Computed: true, + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + }, + "issuer_uri": { + Type: schema.TypeString, + Computed: true, + }, + "okta_idp_id": { + Type: schema.TypeString, + Computed: true, + }, + "pem_file_info": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificates": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "not_after": { + Type: schema.TypeString, + Computed: true, + }, + "not_before": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "file_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "request_binding": { + Type: schema.TypeString, + Computed: true, + }, + "response_signature_algorithm": { + Type: schema.TypeString, + Computed: true, + }, + "sso_debug_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "sso_url": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} +func dataSourceMongoDBAtlasFederatedSettingsIdentityProviderRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + federationSettingsID, federationSettingsIDOk := d.GetOk("federation_settings_id") + + if !federationSettingsIDOk { + return diag.FromErr(errors.New("federation_settings_id must be configured")) + } + + idpID, idpIDOk := d.GetOk("identity_provider_id") + + if !idpIDOk { + return diag.FromErr(errors.New("identity_provider_id must be configured")) + } + + federatedSettingsIdentityProvider, _, err := conn.FederatedSettings.GetIdentityProvider(ctx, federationSettingsID.(string), idpID.(string)) + if err != nil { + return diag.Errorf("error getting federatedSettings IdentityProviders assigned (%s): %s", federationSettingsID, err) + } + + if err := d.Set("acs_url", federatedSettingsIdentityProvider.AcsURL); err != nil { + return diag.FromErr(fmt.Errorf("error setting `acs_url` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("associated_domains", federatedSettingsIdentityProvider.AssociatedDomains); err != nil { + return diag.FromErr(fmt.Errorf("error setting `associated_domains` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("associated_orgs", flattenAssociatedOrgs(federatedSettingsIdentityProvider.AssociatedOrgs)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `associated_orgs` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("display_name", federatedSettingsIdentityProvider.DisplayName); err != nil { + return diag.FromErr(fmt.Errorf("error setting `display_name` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("issuer_uri", federatedSettingsIdentityProvider.IssuerURI); err != nil { + return diag.FromErr(fmt.Errorf("error setting `issuer_uri` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("okta_idp_id", federatedSettingsIdentityProvider.OktaIdpID); err != nil { + return diag.FromErr(fmt.Errorf("error setting `idp_id` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("pem_file_info", flattenPemFileInfo(*federatedSettingsIdentityProvider.PemFileInfo)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `pem_file_info` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("request_binding", federatedSettingsIdentityProvider.RequestBinding); err != nil { + return diag.FromErr(fmt.Errorf("error setting `request_binding` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("response_signature_algorithm", federatedSettingsIdentityProvider.ResponseSignatureAlgorithm); err != nil { + return diag.FromErr(fmt.Errorf("error setting `response_signature_algorithm` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("sso_debug_enabled", federatedSettingsIdentityProvider.SsoDebugEnabled); err != nil { + return diag.FromErr(fmt.Errorf("error setting `sso_debug_enabled` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("sso_url", federatedSettingsIdentityProvider.SsoURL); err != nil { + return diag.FromErr(fmt.Errorf("error setting `sso_url` for federatedSettings IdentityProviders: %s", err)) + } + + if err := d.Set("status", federatedSettingsIdentityProvider.Status); err != nil { + return diag.FromErr(fmt.Errorf("error setting `status` for federatedSettings IdentityProviders: %s", err)) + } + + d.SetId(federatedSettingsIdentityProvider.OktaIdpID) + + return nil +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_provider_test.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_provider_test.go new file mode 100644 index 0000000000..ffd3fe27c7 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_provider_test.go @@ -0,0 +1,45 @@ +package mongodbatlas + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceMongoDBAtlasFederatedSettingsIdentityProvider_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "data.mongodbatlas_federated_settings_identity_provider.test" + federatedSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + idpID = os.Getenv("MONGODB_ATLAS_FEDERATED_IDP_ID") + ) + resource.Test(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasDataSourceFederatedSettingsIdentityProviderConfig(federatedSettingsID, idpID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsIdentityProvidersExists(resourceName), + + resource.TestCheckResourceAttrSet(resourceName, "federation_settings_id"), + resource.TestCheckResourceAttrSet(resourceName, "associated_orgs.#"), + resource.TestCheckResourceAttrSet(resourceName, "acs_url"), + resource.TestCheckResourceAttrSet(resourceName, "display_name"), + resource.TestCheckResourceAttr(resourceName, "display_name", "mongodb_federation_test"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasDataSourceFederatedSettingsIdentityProviderConfig(federatedSettingsID, idpID string) string { + return fmt.Sprintf(` + data "mongodbatlas_federated_settings_identity_provider" "test" { + federation_settings_id = "%[1]s" + identity_provider_id = "%[2]s" + } +`, federatedSettingsID, idpID) +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_providers.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_providers.go new file mode 100644 index 0000000000..3efe2ad67c --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_providers.go @@ -0,0 +1,427 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + "sort" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func dataSourceMongoDBAtlasFederatedSettingsIdentityProviders() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasFederatedSettingsIdentityProvidersRead, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "page_num": { + Type: schema.TypeInt, + Optional: true, + }, + "items_per_page": { + Type: schema.TypeInt, + Optional: true, + }, + "results": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "acs_url": { + Type: schema.TypeString, + Computed: true, + }, + "associated_domains": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "associated_orgs": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "domain_allow_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "domain_restriction_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "identity_provider_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "post_auth_role_grants": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "role_mappings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "external_group_name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "role_assignments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "role": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "user_conflicts": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "email_address": { + Type: schema.TypeString, + Computed: true, + }, + "federation_settings_id": { + Type: schema.TypeString, + Computed: true, + }, + "first_name": { + Type: schema.TypeString, + Computed: true, + }, + "last_name": { + Type: schema.TypeString, + Computed: true, + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "audience_uri": { + Type: schema.TypeString, + Computed: true, + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + }, + "issuer_uri": { + Type: schema.TypeString, + Computed: true, + }, + "okta_idp_id": { + Type: schema.TypeString, + Computed: true, + }, + "pem_file_info": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificates": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "not_after": { + Type: schema.TypeString, + Computed: true, + }, + "not_before": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "file_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "request_binding": { + Type: schema.TypeString, + Computed: true, + }, + "response_signature_algorithm": { + Type: schema.TypeString, + Computed: true, + }, + "sso_debug_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "sso_url": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} +func dataSourceMongoDBAtlasFederatedSettingsIdentityProvidersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + federationSettingsID, federationSettingsIDOk := d.GetOk("federation_settings_id") + + options := &matlas.ListOptions{ + PageNum: d.Get("page_num").(int), + ItemsPerPage: d.Get("items_per_page").(int), + } + + if !federationSettingsIDOk { + return diag.FromErr(errors.New("federation_settings_id must be configured")) + } + + federatedSettingsIdentityProviders, _, err := conn.FederatedSettings.ListIdentityProviders(ctx, federationSettingsID.(string), options) + if err != nil { + return diag.Errorf("error getting federatedSettings IdentityProviders assigned (%s): %s", federationSettingsID, err) + } + + if err := d.Set("results", flattenFederatedSettingsIdentityProvider(federatedSettingsIdentityProviders)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `result` for federatedSettings IdentityProviders: %s", err)) + } + + d.SetId(federationSettingsID.(string)) + + return nil +} + +func flattenFederatedSettingsIdentityProvider(federatedSettingsIdentityProvider []matlas.FederatedSettingsIdentityProvider) []map[string]interface{} { + var federatedSettingsIdentityProviderMap []map[string]interface{} + + if len(federatedSettingsIdentityProvider) > 0 { + federatedSettingsIdentityProviderMap = make([]map[string]interface{}, len(federatedSettingsIdentityProvider)) + + for i := range federatedSettingsIdentityProvider { + federatedSettingsIdentityProviderMap[i] = map[string]interface{}{ + "acs_url": federatedSettingsIdentityProvider[i].AcsURL, + "associated_domains": federatedSettingsIdentityProvider[i].AssociatedDomains, + "associated_orgs": flattenAssociatedOrgs(federatedSettingsIdentityProvider[i].AssociatedOrgs), + "audience_uri": federatedSettingsIdentityProvider[i].AudienceURI, + "display_name": federatedSettingsIdentityProvider[i].DisplayName, + "issuer_uri": federatedSettingsIdentityProvider[i].IssuerURI, + "okta_idp_id": federatedSettingsIdentityProvider[i].OktaIdpID, + "pem_file_info": flattenPemFileInfo(*federatedSettingsIdentityProvider[i].PemFileInfo), + "request_binding": federatedSettingsIdentityProvider[i].RequestBinding, + "response_signature_algorithm": federatedSettingsIdentityProvider[i].ResponseSignatureAlgorithm, + "sso_debug_enabled": federatedSettingsIdentityProvider[i].SsoDebugEnabled, + "sso_url": federatedSettingsIdentityProvider[i].SsoURL, + "status": federatedSettingsIdentityProvider[i].Status, + } + } + } + + return federatedSettingsIdentityProviderMap +} + +func flattenAssociatedOrgs(associatedOrgs []*matlas.AssociatedOrgs) []map[string]interface{} { + var associatedOrgsMap []map[string]interface{} + + if len(associatedOrgs) == 0 { + return nil + } + associatedOrgsMap = make([]map[string]interface{}, len(associatedOrgs)) + + for i := range associatedOrgs { + if associatedOrgs[i].UserConflicts == nil { + associatedOrgsMap[i] = map[string]interface{}{ + "domain_allow_list": associatedOrgs[i].DomainAllowList, + "domain_restriction_enabled": associatedOrgs[i].DomainRestrictionEnabled, + "identity_provider_id": associatedOrgs[i].IdentityProviderID, + "org_id": associatedOrgs[i].OrgID, + "post_auth_role_grants": associatedOrgs[i].PostAuthRoleGrants, + "role_mappings": flattenRoleMappings(associatedOrgs[i].RoleMappings), + "user_conflicts": nil, + } + } else { + associatedOrgsMap[i] = map[string]interface{}{ + "domain_allow_list": associatedOrgs[i].DomainAllowList, + "domain_restriction_enabled": associatedOrgs[i].DomainRestrictionEnabled, + "identity_provider_id": associatedOrgs[i].IdentityProviderID, + "org_id": associatedOrgs[i].OrgID, + "post_auth_role_grants": associatedOrgs[i].PostAuthRoleGrants, + "role_mappings": flattenRoleMappings(associatedOrgs[i].RoleMappings), + "user_conflicts": flattenUserConflicts(*associatedOrgs[i].UserConflicts), + } + } + } + + return associatedOrgsMap +} + +func flattenUserConflicts(userConflicts matlas.UserConflicts) []map[string]interface{} { + var userConflictsMap []map[string]interface{} + + if len(userConflicts) == 0 { + return nil + } + userConflictsMap = make([]map[string]interface{}, len(userConflicts)) + + for i := range userConflicts { + userConflictsMap[i] = map[string]interface{}{ + "email_address": userConflicts[i].EmailAddress, + "federation_settings_id": userConflicts[i].FederationSettingsID, + "first_name": userConflicts[i].FirstName, + "last_name": userConflicts[i].LastName, + "user_id": userConflicts[i].UserID, + } + } + + return userConflictsMap +} + +func flattenPemFileInfo(pemFileInfo matlas.PemFileInfo) []map[string]interface{} { + var pemFileInfoMap []map[string]interface{} + + if len(pemFileInfo.Certificates) > 0 { + pemFileInfoMap = make([]map[string]interface{}, 1) + + pemFileInfoMap[0] = map[string]interface{}{ + "certificates": flattenFederatedSettingsCertificates(pemFileInfo.Certificates), + "file_name": pemFileInfo.FileName, + } + } + + return pemFileInfoMap +} + +func flattenFederatedSettingsCertificates(certificates []*matlas.Certificates) []map[string]interface{} { + var certificatesMap []map[string]interface{} + + if len(certificates) > 0 { + certificatesMap = make([]map[string]interface{}, len(certificates)) + + for i := range certificates { + certificatesMap[i] = map[string]interface{}{ + "not_after": certificates[i].NotAfter.String(), + "not_before": certificates[i].NotBefore.String(), + } + } + } + + return certificatesMap +} + +type mRoleAssignment []*matlas.RoleAssignments + +func (ra mRoleAssignment) Len() int { return len(ra) } +func (ra mRoleAssignment) Swap(i, j int) { ra[i], ra[j] = ra[j], ra[i] } +func (ra mRoleAssignment) Less(i, j int) bool { + compareVal := strings.Compare(ra[i].OrgID, ra[j].OrgID) + + if compareVal != 0 { + return compareVal < 0 + } + + compareVal = strings.Compare(ra[i].GroupID, ra[j].GroupID) + + if compareVal != 0 { + return compareVal < 0 + } + + return ra[i].Role < ra[j].Role +} + +type roleMappingsByGroupName []*matlas.RoleMappings + +func (ra roleMappingsByGroupName) Len() int { return len(ra) } +func (ra roleMappingsByGroupName) Swap(i, j int) { ra[i], ra[j] = ra[j], ra[i] } + +func (ra roleMappingsByGroupName) Less(i, j int) bool { + return ra[i].ExternalGroupName < ra[j].ExternalGroupName +} + +func flattenRoleMappings(roleMappings []*matlas.RoleMappings) []map[string]interface{} { + sort.Sort(roleMappingsByGroupName(roleMappings)) + + var roleMappingsMap []map[string]interface{} + + if len(roleMappings) > 0 { + roleMappingsMap = make([]map[string]interface{}, len(roleMappings)) + + for i := range roleMappings { + roleMappingsMap[i] = map[string]interface{}{ + "external_group_name": roleMappings[i].ExternalGroupName, + "id": roleMappings[i].ID, + "role_assignments": flattenRoleAssignments(roleMappings[i].RoleAssignments), + } + } + } + + return roleMappingsMap +} + +func flattenRoleAssignments(roleAssignments []*matlas.RoleAssignments) []map[string]interface{} { + sort.Sort(mRoleAssignment(roleAssignments)) + + var roleAssignmentsMap []map[string]interface{} + + if len(roleAssignments) > 0 { + roleAssignmentsMap = make([]map[string]interface{}, len(roleAssignments)) + + for i := range roleAssignments { + roleAssignmentsMap[i] = map[string]interface{}{ + "group_id": roleAssignments[i].GroupID, + "org_id": roleAssignments[i].OrgID, + "role": roleAssignments[i].Role, + } + } + } + + return roleAssignmentsMap +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_providers_test.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_providers_test.go new file mode 100644 index 0000000000..33dd04a7df --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_identity_providers_test.go @@ -0,0 +1,69 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceMongoDBAtlasFederatedSettingsIdentityProviders_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "data.mongodbatlas_federated_settings_identity_providers.test" + federatedSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasDataSourceFederatedSettingsIdentityProvidersConfig(federatedSettingsID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsIdentityProvidersExists(resourceName), + + resource.TestCheckResourceAttrSet(resourceName, "federation_settings_id"), + resource.TestCheckResourceAttrSet(resourceName, "results.#"), + resource.TestCheckResourceAttrSet(resourceName, "results.0.acs_url"), + resource.TestCheckResourceAttrSet(resourceName, "results.0.display_name"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasDataSourceFederatedSettingsIdentityProvidersConfig(federatedSettingsID string) string { + return fmt.Sprintf(` + data "mongodbatlas_federated_settings_identity_providers" "test" { + federation_settings_id = "%[1]s" + page_num = 1 + items_per_page = 100 + } +`, federatedSettingsID) +} + +func testAccCheckMongoDBAtlasFederatedSettingsIdentityProvidersExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + _, _, err := conn.FederatedSettings.ListIdentityProviders(context.Background(), rs.Primary.Attributes["federation_settings_id"], nil) + if err != nil { + return fmt.Errorf("FederatedSettingsIdentityProviders (%s) does not exist", rs.Primary.ID) + } + + return nil + } +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mapping.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mapping.go new file mode 100644 index 0000000000..d533d5cc87 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mapping.go @@ -0,0 +1,98 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMapping() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingRead, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "org_id": { + Type: schema.TypeString, + Required: true, + }, + "role_mapping_id": { + Type: schema.TypeString, + Required: true, + }, + + "external_group_name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "role_assignments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "role": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} +func dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + federationSettingsID, federationSettingsIDOk := d.GetOk("federation_settings_id") + + if !federationSettingsIDOk { + return diag.FromErr(errors.New("federation_settings_id must be configured")) + } + + orgID, orgIDOk := d.GetOk("org_id") + + if !orgIDOk { + return diag.FromErr(errors.New("org_id must be configured")) + } + + roleMappingID, roleMappingOk := d.GetOk("role_mapping_id") + + if !roleMappingOk { + return diag.FromErr(errors.New("role_mapping_id must be configured")) + } + + federatedSettingsOrganizationRoleMapping, _, err := conn.FederatedSettings.GetRoleMapping(ctx, federationSettingsID.(string), orgID.(string), roleMappingID.(string)) + if err != nil { + return diag.Errorf("error getting federatedSettings Role Mapping assigned (%s): %s", federationSettingsID, err) + } + + if err := d.Set("external_group_name", federatedSettingsOrganizationRoleMapping.ExternalGroupName); err != nil { + return diag.FromErr(fmt.Errorf("error setting `result` for federatedSettings Role Mapping: %s", err)) + } + + if err := d.Set("role_assignments", flattenRoleAssignments(federatedSettingsOrganizationRoleMapping.RoleAssignments)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `result` for federatedSettings Role Mapping: %s", err)) + } + + d.SetId(federatedSettingsOrganizationRoleMapping.ID) + + return nil +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mapping_test.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mapping_test.go new file mode 100644 index 0000000000..c10322c5e3 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mapping_test.go @@ -0,0 +1,49 @@ +package mongodbatlas + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func TestAccDataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMapping_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + federatedSettingsOrganizationRoleMapping matlas.FederatedSettingsOrganizationRoleMapping + resourceName = "data.mongodbatlas_federated_settings_org_role_mapping.test" + federatedSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + roleMappingID = os.Getenv("MONGODB_ATLAS_FEDERATED_ROLE_MAPPING_ID") + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationRoleMappingConfig(federatedSettingsID, orgID, roleMappingID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingExists(resourceName, &federatedSettingsOrganizationRoleMapping), + resource.TestCheckResourceAttrSet(resourceName, "federation_settings_id"), + resource.TestCheckResourceAttrSet(resourceName, "external_group_name"), + resource.TestCheckResourceAttrSet(resourceName, "role_assignments.#"), + resource.TestCheckResourceAttr(resourceName, "org_id", orgID), + resource.TestCheckResourceAttr(resourceName, "external_group_name", "group2"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationRoleMappingConfig(federatedSettingsID, orgID, roleMappingID string) string { + return fmt.Sprintf(` + data "mongodbatlas_federated_settings_org_role_mapping" "test" { + federation_settings_id = "%[1]s" + org_id = "%[2]s" + role_mapping_id = "%[3]s" + } +`, federatedSettingsID, orgID, roleMappingID) +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mappings.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mappings.go new file mode 100644 index 0000000000..6028a6efc8 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mappings.go @@ -0,0 +1,123 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMappings() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingsRead, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "org_id": { + Type: schema.TypeString, + Required: true, + }, + "page_num": { + Type: schema.TypeInt, + Optional: true, + }, + "items_per_page": { + Type: schema.TypeInt, + Optional: true, + }, + "results": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "external_group_name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "role_assignments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Type: schema.TypeString, + Computed: true, + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + }, + "role": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} +func dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + federationSettingsID, federationSettingsIDOk := d.GetOk("federation_settings_id") + + if !federationSettingsIDOk { + return diag.FromErr(errors.New("federation_settings_id must be configured")) + } + + orgID, orgIDOk := d.GetOk("org_id") + + if !orgIDOk { + return diag.FromErr(errors.New("org_id must be configured")) + } + + options := &matlas.ListOptions{ + PageNum: d.Get("page_num").(int), + ItemsPerPage: d.Get("items_per_page").(int), + } + + federatedSettingsOrganizationRoleMappings, _, err := conn.FederatedSettings.ListRoleMappings(ctx, federationSettingsID.(string), orgID.(string), options) + if err != nil { + return diag.Errorf("error getting federatedSettings Role Mapping: assigned (%s): %s", federationSettingsID, err) + } + + if err := d.Set("results", flattenFederatedSettingsOrganizationRoleMappings(federatedSettingsOrganizationRoleMappings)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `result` for federatedSettings Role Mapping:: %s", err)) + } + + d.SetId(federationSettingsID.(string)) + + return nil +} + +func flattenFederatedSettingsOrganizationRoleMappings(federatedSettingsOrganizationRoleMapping *matlas.FederatedSettingsOrganizationRoleMappings) []map[string]interface{} { + var federatedSettingsOrganizationRoleMappingMap []map[string]interface{} + + if federatedSettingsOrganizationRoleMapping.TotalCount > 0 { + federatedSettingsOrganizationRoleMappingMap = make([]map[string]interface{}, federatedSettingsOrganizationRoleMapping.TotalCount) + + for i := range federatedSettingsOrganizationRoleMapping.Results { + federatedSettingsOrganizationRoleMappingMap[i] = map[string]interface{}{ + "external_group_name": federatedSettingsOrganizationRoleMapping.Results[i].ExternalGroupName, + "id": federatedSettingsOrganizationRoleMapping.Results[i].ID, + "role_assignments": flattenRoleAssignments(federatedSettingsOrganizationRoleMapping.Results[i].RoleAssignments), + } + } + } + + return federatedSettingsOrganizationRoleMappingMap +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mappings_test.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mappings_test.go new file mode 100644 index 0000000000..0bd47da0a8 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_organization_role_mappings_test.go @@ -0,0 +1,70 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMappings_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "data.mongodbatlas_federated_settings_org_role_mappings.test" + federatedSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationRoleMappingsConfig(federatedSettingsID, orgID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingsExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "federation_settings_id"), + resource.TestCheckResourceAttrSet(resourceName, "results.#"), + resource.TestCheckResourceAttrSet(resourceName, "results.0.external_group_name"), + resource.TestCheckResourceAttrSet(resourceName, "results.0.role_assignments.#"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasDataSourceFederatedSettingsOrganizationRoleMappingsConfig(federatedSettingsID, orgID string) string { + return fmt.Sprintf(` + data "mongodbatlas_federated_settings_org_role_mappings" "test" { + federation_settings_id = "%[1]s" + org_id = "%[2]s" + page_num = 1 + items_per_page = 100 + } +`, federatedSettingsID, orgID) +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingsExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + _, _, err := conn.FederatedSettings.ListRoleMappings(context.Background(), rs.Primary.Attributes["federation_settings_id"], rs.Primary.Attributes["org_id"], nil) + if err != nil { + return fmt.Errorf("FederatedSettingsOrganizationRoleMappings (%s) does not exist", rs.Primary.ID) + } + + return nil + } +} diff --git a/mongodbatlas/data_source_mongodbatlas_federated_settings_test.go b/mongodbatlas/data_source_mongodbatlas_federated_settings_test.go new file mode 100644 index 0000000000..58635a8328 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_federated_settings_test.go @@ -0,0 +1,72 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func TestAccDataSourceMongoDBAtlasFederatedSettings_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + federatedSettings matlas.FederatedSettings + resourceName = "data.mongodbatlas_federated_settings.test" + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasDataSourceFederatedSettingsConfig(orgID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsExists(resourceName, &federatedSettings), + + resource.TestCheckResourceAttrSet(resourceName, "org_id"), + resource.TestCheckResourceAttrSet(resourceName, "identity_provider_id"), + resource.TestCheckResourceAttrSet(resourceName, "identity_provider_status"), + resource.TestCheckResourceAttrSet(resourceName, "has_role_mappings"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasDataSourceFederatedSettingsConfig(orgID string) string { + return fmt.Sprintf(` + data "mongodbatlas_federated_settings" "test" { + org_id = "%[1]s" + } +`, orgID) +} + +func testAccCheckMongoDBAtlasFederatedSettingsExists(resourceName string, federatedSettings *matlas.FederatedSettings) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + federatedSettingsRes, _, err := conn.FederatedSettings.Get(context.Background(), rs.Primary.Attributes["org_id"]) + if err != nil { + return fmt.Errorf("FederatedSettings (%s) does not exist", rs.Primary.ID) + } + + federatedSettings = federatedSettingsRes + + return nil + } +} diff --git a/mongodbatlas/data_source_mongodbatlas_private_endpoint_regional_mode.go b/mongodbatlas/data_source_mongodbatlas_private_endpoint_regional_mode.go new file mode 100644 index 0000000000..a2b0c210b9 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_private_endpoint_regional_mode.go @@ -0,0 +1,51 @@ +package mongodbatlas + +import ( + "context" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceMongoDBAtlasPrivateEndpointRegionalMode() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMongoDBAtlasPrivateEndpointRegionalModeRead, + Schema: map[string]*schema.Schema{ + "project_id": { + Type: schema.TypeString, + Required: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + } +} + +func dataSourceMongoDBAtlasPrivateEndpointRegionalModeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + projectID := d.Get("project_id").(string) + + setting, _, err := conn.PrivateEndpoints.GetRegionalizedPrivateEndpointSetting(ctx, projectID) + if err != nil { + // case 404 + // deleted in the backend case + if strings.Contains(err.Error(), "404") { + d.SetId("") + return nil + } + + return diag.Errorf("error getting private endpoint regional mode: %s", err) + } + + if err := d.Set("enabled", setting.Enabled); err != nil { + return diag.Errorf("error setting `enabled` for enabled (%s): %s", d.Id(), err) + } + + d.SetId(projectID) + + return nil +} diff --git a/mongodbatlas/data_source_mongodbatlas_private_endpoint_regional_mode_test.go b/mongodbatlas/data_source_mongodbatlas_private_endpoint_regional_mode_test.go new file mode 100644 index 0000000000..a716ec79e0 --- /dev/null +++ b/mongodbatlas/data_source_mongodbatlas_private_endpoint_regional_mode_test.go @@ -0,0 +1,57 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceMongoDBAtlasPrivateEndpointRegionalMode_basic(t *testing.T) { + resourceName := "mongodbatlas_private_endpoint_regional_mode.test" + projectID := os.Getenv("MONGODB_ATLAS_PROJECT_ID") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasPrivateEndpointRegionalModeDataSourceConfig(projectID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasPrivateEndpointRegionalModeExists(resourceName), + testAccMongoDBAtlasPrivateEndpointRegionalModeUnmanagedResource(resourceName, projectID), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasPrivateEndpointRegionalModeUnmanagedResource(resourceName, projectID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + setting, _, err := conn.PrivateEndpoints.GetRegionalizedPrivateEndpointSetting(context.Background(), projectID) + + if err != nil || setting == nil { + return fmt.Errorf("Could not get regionalized private endpoint setting for project_id (%s)", projectID) + } + + return resource.TestCheckResourceAttr(resourceName, "enabled", strconv.FormatBool(setting.Enabled))(s) + } +} + +func testAccMongoDBAtlasPrivateEndpointRegionalModeDataSourceConfig(projectID string) string { + return fmt.Sprintf(` + resource "mongodbatlas_private_endpoint_regional_mode" "test" { + project_id = data.mongodbatlas_private_endpoint_regional_mode.test.project_id + } + + data "mongodbatlas_private_endpoint_regional_mode" "test" { + project_id = %q + } + `, projectID) +} diff --git a/mongodbatlas/data_source_mongodbatlas_project.go b/mongodbatlas/data_source_mongodbatlas_project.go index f540b704f5..6ca0c7a612 100644 --- a/mongodbatlas/data_source_mongodbatlas_project.go +++ b/mongodbatlas/data_source_mongodbatlas_project.go @@ -81,6 +81,26 @@ func dataSourceMongoDBAtlasProject() *schema.Resource { }, }, }, + "is_collect_database_specifics_statistics_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_data_explorer_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_performance_advisor_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_realtime_performance_panel_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_schema_advisor_enabled": { + Type: schema.TypeBool, + Computed: true, + }, }, } } @@ -147,6 +167,10 @@ func dataSourceMongoDBAtlasProjectRead(ctx context.Context, d *schema.ResourceDa } log.Println("[WARN] `api_keys` will be empty because the user has no permissions to read the api keys endpoint") } + projectSettings, _, err := conn.Projects.GetProjectSettings(ctx, project.ID) + if err != nil { + return diag.Errorf("error getting project's settings assigned (%s): %s", projectID, err) + } if err := d.Set("org_id", project.OrgID); err != nil { return diag.Errorf(errorProjectSetting, `org_id`, project.ID, err) @@ -167,6 +191,21 @@ func dataSourceMongoDBAtlasProjectRead(ctx context.Context, d *schema.ResourceDa if err := d.Set("api_keys", flattenAPIKeys(apiKeys)); err != nil { return diag.Errorf(errorProjectSetting, `api_keys`, project.ID, err) } + if err := d.Set("is_collect_database_specifics_statistics_enabled", projectSettings.IsCollectDatabaseSpecificsStatisticsEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_collect_database_specifics_statistics_enabled`, project.ID, err) + } + if err := d.Set("is_data_explorer_enabled", projectSettings.IsDataExplorerEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_data_explorer_enabled`, project.ID, err) + } + if err := d.Set("is_performance_advisor_enabled", projectSettings.IsPerformanceAdvisorEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_performance_advisor_enabled`, project.ID, err) + } + if err := d.Set("is_realtime_performance_panel_enabled", projectSettings.IsRealtimePerformancePanelEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_realtime_performance_panel_enabled`, project.ID, err) + } + if err := d.Set("is_schema_advisor_enabled", projectSettings.IsSchemaAdvisorEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_schema_advisor_enabled`, project.ID, err) + } d.SetId(project.ID) diff --git a/mongodbatlas/data_source_mongodbatlas_project_test.go b/mongodbatlas/data_source_mongodbatlas_project_test.go index db1715be10..c8cb9f2283 100644 --- a/mongodbatlas/data_source_mongodbatlas_project_test.go +++ b/mongodbatlas/data_source_mongodbatlas_project_test.go @@ -110,6 +110,61 @@ func TestAccDataSourceMongoDBAtlasProject_byName(t *testing.T) { }) } +func TestAccDataSourceMongoDBAtlasProject_defaultFlags(t *testing.T) { + projectName := fmt.Sprintf("test-datasource-project-%s", acctest.RandString(10)) + orgID := os.Getenv("MONGODB_ATLAS_ORG_ID") + teamsIds := strings.Split(os.Getenv("MONGODB_ATLAS_TEAMS_IDS"), ",") + apiKeysIds := strings.Split(os.Getenv("MONGODB_ATLAS_API_KEYS_IDS"), ",") + if len(teamsIds) < 2 { + t.Skip("`MONGODB_ATLAS_TEAMS_IDS` must have 2 team ids for this acceptance testing") + } + if len(apiKeysIds) < 2 { + t.Skip("`MONGODB_ATLAS_API_KEYS_IDS` must have 2 api key ids for this acceptance testing") + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); checkTeamsIds(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasProjectConfigWithDSByName(projectName, orgID, + []*matlas.ProjectTeam{ + { + TeamID: teamsIds[0], + RoleNames: []string{"GROUP_READ_ONLY", "GROUP_DATA_ACCESS_ADMIN"}, + }, + { + + TeamID: teamsIds[1], + RoleNames: []string{"GROUP_DATA_ACCESS_ADMIN", "GROUP_OWNER"}, + }, + }, + []*apiKey{ + { + id: apiKeysIds[0], + roles: []string{"GROUP_READ_ONLY"}, + }, + { + id: apiKeysIds[1], + roles: []string{"GROUP_OWNER"}, + }, + }, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "name"), + resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "org_id"), + resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "is_collect_database_specifics_statistics_enabled"), + resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "is_data_explorer_enabled"), + resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "is_performance_advisor_enabled"), + resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "is_realtime_performance_panel_enabled"), + resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "is_schema_advisor_enabled"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccMongoDBAtlasProjectConfigWithDSByID(projectName, orgID string, teams []*matlas.ProjectTeam, apiKeys []*apiKey) string { return fmt.Sprintf(` %s diff --git a/mongodbatlas/data_source_mongodbatlas_projects.go b/mongodbatlas/data_source_mongodbatlas_projects.go index 3b554e558f..e9eed3515d 100644 --- a/mongodbatlas/data_source_mongodbatlas_projects.go +++ b/mongodbatlas/data_source_mongodbatlas_projects.go @@ -86,6 +86,26 @@ func dataSourceMongoDBAtlasProjects() *schema.Resource { }, }, }, + "is_collect_database_specifics_statistics_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_data_explorer_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_performance_advisor_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_realtime_performance_panel_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "is_schema_advisor_enabled": { + Type: schema.TypeBool, + Computed: true, + }, }, }, }, @@ -139,6 +159,12 @@ func flattenProjects(ctx context.Context, conn *matlas.Client, projects []*matla if err != nil { fmt.Printf("[WARN] error getting project's api keys (%s): %s", project.ID, err) } + + projectSettings, _, err := conn.Projects.GetProjectSettings(ctx, project.ID) + if err != nil { + fmt.Printf("[WARN] error getting project's settings assigned (%s): %s", project.ID, err) + } + results[k] = map[string]interface{}{ "id": project.ID, "org_id": project.OrgID, @@ -147,6 +173,11 @@ func flattenProjects(ctx context.Context, conn *matlas.Client, projects []*matla "created": project.Created, "teams": flattenTeams(teams), "api_keys": flattenAPIKeys(apiKeys), + "is_collect_database_specifics_statistics_enabled": projectSettings.IsCollectDatabaseSpecificsStatisticsEnabled, + "is_data_explorer_enabled": projectSettings.IsDataExplorerEnabled, + "is_performance_advisor_enabled": projectSettings.IsPerformanceAdvisorEnabled, + "is_realtime_performance_panel_enabled": projectSettings.IsRealtimePerformancePanelEnabled, + "is_schema_advisor_enabled": projectSettings.IsSchemaAdvisorEnabled, } } } diff --git a/mongodbatlas/data_source_mongodbatlas_third_party_integration.go b/mongodbatlas/data_source_mongodbatlas_third_party_integration.go index cc73a1a0cb..1279463632 100644 --- a/mongodbatlas/data_source_mongodbatlas_third_party_integration.go +++ b/mongodbatlas/data_source_mongodbatlas_third_party_integration.go @@ -105,6 +105,29 @@ func thirdPartyIntegrationSchema() *schema.Resource { Sensitive: true, Computed: true, }, + "microsoft_teams_webhook_url": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + }, + "user_name": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + }, + "service_discovery": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + }, + "scheme": { + Type: schema.TypeString, + Optional: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, }, } } diff --git a/mongodbatlas/data_source_mongodbatlas_third_party_integration_test.go b/mongodbatlas/data_source_mongodbatlas_third_party_integration_test.go index 325452194e..7b4643057c 100644 --- a/mongodbatlas/data_source_mongodbatlas_third_party_integration_test.go +++ b/mongodbatlas/data_source_mongodbatlas_third_party_integration_test.go @@ -84,6 +84,27 @@ const ( url = "%[4]s" } ` + + MICROSOFTTEAMS = ` + resource "mongodbatlas_third_party_integration" "%[1]s" { + project_id = "%[2]s" + type = "%[3]s" + microsoft_teams_webhook_url = "%[4]s" + } + ` + + PROMETHEUS = ` + resource "mongodbatlas_third_party_integration" "%[1]s" { + project_id = "%[2]s" + type = "%[3]s" + user_name = "%[4]s" + password = "%[5]s" + service_discovery = "%[6]s" + scheme = "%[7]s" + enabled = "%[8]s" + } + ` + alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" numeric = "0123456789" alphaNum = alphabet + numeric @@ -202,6 +223,24 @@ func testAccMongoDBAtlasThirdPartyIntegrationResourceConfig(config *thirdPartyCo config.Integration.Type, config.Integration.URL, ) + case "MICROSOFTTEAMS": + return fmt.Sprintf(WEBHOOK, + config.Name, + config.ProjectID, + config.Integration.Type, + config.Integration.MicrosoftTeamsWebhookURL, + ) + case "PROMETHEUS": + return fmt.Sprintf(WEBHOOK, + config.Name, + config.ProjectID, + config.Integration.Type, + config.Integration.UserName, + config.Integration.Password, + config.Integration.ServiceDiscovery, + config.Integration.Scheme, + config.Integration.Enabled, + ) default: return fmt.Sprintf(Unknown3rdParty, config.Name, diff --git a/mongodbatlas/data_source_mongodbatlas_third_party_integrations.go b/mongodbatlas/data_source_mongodbatlas_third_party_integrations.go index 313a46efbd..2f693be83f 100644 --- a/mongodbatlas/data_source_mongodbatlas_third_party_integrations.go +++ b/mongodbatlas/data_source_mongodbatlas_third_party_integrations.go @@ -64,28 +64,34 @@ func flattenIntegrations(integrations *matlas.ThirdPartyIntegrations, projectID func integrationToSchema(integration *matlas.ThirdPartyIntegration) map[string]interface{} { out := map[string]interface{}{ - "type": integration.Type, - "license_key": integration.LicenseKey, - "account_id": integration.AccountID, - "write_token": integration.WriteToken, - "read_token": integration.ReadToken, - "api_key": integration.APIKey, - "region": integration.Region, - "service_key": integration.ServiceKey, - "api_token": integration.APIToken, - "team_name": integration.TeamName, - "channel_name": integration.ChannelName, - "routing_key": integration.RoutingKey, - "flow_name": integration.FlowName, - "org_name": integration.OrgName, - "url": integration.URL, - "secret": integration.Secret, + "type": integration.Type, + "license_key": integration.LicenseKey, + "account_id": integration.AccountID, + "write_token": integration.WriteToken, + "read_token": integration.ReadToken, + "api_key": integration.APIKey, + "region": integration.Region, + "service_key": integration.ServiceKey, + "api_token": integration.APIToken, + "team_name": integration.TeamName, + "channel_name": integration.ChannelName, + "routing_key": integration.RoutingKey, + "flow_name": integration.FlowName, + "org_name": integration.OrgName, + "url": integration.URL, + "secret": integration.Secret, + "microsoft_teams_webhook_url": integration.MicrosoftTeamsWebhookURL, + "user_name": integration.UserName, + "password": integration.Password, + "service_discovery": integration.ServiceDiscovery, + "scheme": integration.Scheme, + "enabled": integration.Enabled, } // removing optional empty values, terraform complains about unexpected values even though they're empty optionals := []string{"license_key", "account_id", "write_token", "read_token", "api_key", "region", "service_key", "api_token", - "team_name", "channel_name", "flow_name", "org_name", "url", "secret"} + "team_name", "channel_name", "flow_name", "org_name", "url", "secret", "password"} for _, attr := range optionals { if val, ok := out[attr]; ok { @@ -166,6 +172,30 @@ func schemaToIntegration(in *schema.ResourceData) (out *matlas.ThirdPartyIntegra out.Secret = secret.(string) } + if microsoftTeamsWebhookURL, ok := in.GetOk("microsoft_teams_webhook_url"); ok { + out.MicrosoftTeamsWebhookURL = microsoftTeamsWebhookURL.(string) + } + + if userName, ok := in.GetOk("user_name"); ok { + out.UserName = userName.(string) + } + + if password, ok := in.GetOk("password"); ok { + out.Password = password.(string) + } + + if serviceDiscovery, ok := in.GetOk("service_discovery"); ok { + out.ServiceDiscovery = serviceDiscovery.(string) + } + + if scheme, ok := in.GetOk("scheme"); ok { + out.Scheme = scheme.(string) + } + + if enabled, ok := in.GetOk("enabled"); ok { + out.Enabled = enabled.(bool) + } + return out } @@ -229,4 +259,28 @@ func updateIntegrationFromSchema(d *schema.ResourceData, integration *matlas.Thi if d.HasChange("secret") { integration.Secret = d.Get("secret").(string) } + + if d.HasChange("microsoft_teams_webhook_url") { + integration.MicrosoftTeamsWebhookURL = d.Get("microsoft_teams_webhook_url").(string) + } + + if d.HasChange("user_name") { + integration.UserName = d.Get("user_name").(string) + } + + if d.HasChange("password") { + integration.Password = d.Get("password").(string) + } + + if d.HasChange("service_discovery") { + integration.ServiceDiscovery = d.Get("service_discovery").(string) + } + + if d.HasChange("scheme") { + integration.Scheme = d.Get("scheme").(string) + } + + if d.HasChange("enabled") { + integration.Enabled = d.Get("enabled").(bool) + } } diff --git a/mongodbatlas/data_source_mongodbatlas_x509_authentication_database_user.go b/mongodbatlas/data_source_mongodbatlas_x509_authentication_database_user.go index c1582e2477..b542429383 100644 --- a/mongodbatlas/data_source_mongodbatlas_x509_authentication_database_user.go +++ b/mongodbatlas/data_source_mongodbatlas_x509_authentication_database_user.go @@ -66,7 +66,7 @@ func dataSourceMongoDBAtlasX509AuthDBUserRead(ctx context.Context, d *schema.Res username := d.Get("username").(string) if username != "" { - certificates, _, err := conn.X509AuthDBUsers.GetUserCertificates(ctx, projectID, username) + certificates, _, err := conn.X509AuthDBUsers.GetUserCertificates(ctx, projectID, username, nil) if err != nil { return diag.FromErr(fmt.Errorf(errorX509AuthDBUsersRead, username, projectID, err)) } diff --git a/mongodbatlas/provider.go b/mongodbatlas/provider.go index 8824ea2dee..caeb93b54c 100644 --- a/mongodbatlas/provider.go +++ b/mongodbatlas/provider.go @@ -96,6 +96,7 @@ func getDataSourcesMap() map[string]*schema.Resource { "mongodbatlas_global_cluster_config": dataSourceMongoDBAtlasGlobalCluster(), "mongodbatlas_alert_configuration": dataSourceMongoDBAtlasAlertConfiguration(), "mongodbatlas_x509_authentication_database_user": dataSourceMongoDBAtlasX509AuthDBUser(), + "mongodbatlas_private_endpoint_regional_mode": dataSourceMongoDBAtlasPrivateEndpointRegionalMode(), "mongodbatlas_privatelink_endpoint": dataSourceMongoDBAtlasPrivateLinkEndpoint(), "mongodbatlas_privatelink_endpoint_service": dataSourceMongoDBAtlasPrivateEndpointServiceLink(), "mongodbatlas_privatelink_endpoint_service_adl": dataSourceMongoDBAtlasPrivateLinkEndpointServiceADL(), @@ -128,6 +129,13 @@ func getDataSourcesMap() map[string]*schema.Resource { "mongodbatlas_cloud_backup_snapshot_export_buckets": datasourceMongoDBAtlasCloudBackupSnapshotExportBuckets(), "mongodbatlas_cloud_backup_snapshot_export_job": datasourceMongoDBAtlasCloudBackupSnapshotExportJob(), "mongodbatlas_cloud_backup_snapshot_export_jobs": datasourceMongoDBAtlasCloudBackupSnapshotExportJobs(), + "mongodbatlas_federated_settings": dataSourceMongoDBAtlasFederatedSettings(), + "mongodbatlas_federated_settings_identity_provider": dataSourceMongoDBAtlasFederatedSettingsIdentityProvider(), + "mongodbatlas_federated_settings_identity_providers": dataSourceMongoDBAtlasFederatedSettingsIdentityProviders(), + "mongodbatlas_federated_settings_org_config": dataSourceMongoDBAtlasFederatedSettingsOrganizationConfig(), + "mongodbatlas_federated_settings_org_configs": dataSourceMongoDBAtlasFederatedSettingsOrganizationConfigs(), + "mongodbatlas_federated_settings_org_role_mapping": dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMapping(), + "mongodbatlas_federated_settings_org_role_mappings": dataSourceMongoDBAtlasFederatedSettingsOrganizationRoleMappings(), } return dataSourcesMap } @@ -152,6 +160,7 @@ func getResourcesMap() map[string]*schema.Resource { "mongodbatlas_global_cluster_config": resourceMongoDBAtlasGlobalCluster(), "mongodbatlas_alert_configuration": resourceMongoDBAtlasAlertConfiguration(), "mongodbatlas_x509_authentication_database_user": resourceMongoDBAtlasX509AuthDBUser(), + "mongodbatlas_private_endpoint_regional_mode": resourceMongoDBAtlasPrivateEndpointRegionalMode(), "mongodbatlas_privatelink_endpoint": resourceMongoDBAtlasPrivateLinkEndpoint(), "mongodbatlas_privatelink_endpoint_service": resourceMongoDBAtlasPrivateEndpointServiceLink(), "mongodbatlas_privatelink_endpoint_service_adl": resourceMongoDBAtlasPrivateLinkEndpointServiceADL(), @@ -175,6 +184,9 @@ func getResourcesMap() map[string]*schema.Resource { "mongodbatlas_cloud_backup_snapshot_restore_job": resourceMongoDBAtlasCloudBackupSnapshotRestoreJob(), "mongodbatlas_cloud_backup_snapshot_export_bucket": resourceMongoDBAtlasCloudBackupSnapshotExportBucket(), "mongodbatlas_cloud_backup_snapshot_export_job": resourceMongoDBAtlasCloudBackupSnapshotExportJob(), + "mongodbatlas_federated_settings_org_config": resourceMongoDBAtlasFederatedSettingsOrganizationConfig(), + "mongodbatlas_federated_settings_org_role_mapping": resourceMongoDBAtlasFederatedSettingsOrganizationRoleMapping(), + "mongodbatlas_federated_settings_identity_provider": resourceMongoDBAtlasFederatedSettingsIdentityProvider(), } return resourcesMap } diff --git a/mongodbatlas/provider_test.go b/mongodbatlas/provider_test.go index 3cae5035f7..228094a1a3 100644 --- a/mongodbatlas/provider_test.go +++ b/mongodbatlas/provider_test.go @@ -198,3 +198,11 @@ func checkLDAP(t *testing.T) { t.Fatal("`MONGODB_ATLAS_LDAP_HOSTNAME`, `MONGODB_ATLAS_LDAP_USERNAME`, `MONGODB_ATLAS_LDAP_PASSWORD` and `MONGODB_ATLAS_LDAP_PORT` must be set for ldap configuration/verify acceptance testing") } } + +func checkFederatedSettings(t *testing.T) { + if os.Getenv("MONGODB_ATLAS_FEDERATED_PROJECT_ID") == "" || + os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") == "" || + os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") == "" { + t.Fatal("`MONGODB_ATLAS_FEDERATED_PROJECT_ID`, `MONGODB_ATLAS_FEDERATED_ORG_ID` and `MONGODB_ATLAS_FEDERATION_SETTINGS_ID` must be set for federated settings/verify acceptance testing") + } +} diff --git a/mongodbatlas/resource_mongodbatlas_auditing.go b/mongodbatlas/resource_mongodbatlas_auditing.go index f450043a45..40296cd684 100644 --- a/mongodbatlas/resource_mongodbatlas_auditing.go +++ b/mongodbatlas/resource_mongodbatlas_auditing.go @@ -141,6 +141,18 @@ func resourceMongoDBAtlasAuditingUpdate(ctx context.Context, d *schema.ResourceD } func resourceMongoDBAtlasAuditingDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get the client connection. + conn := meta.(*MongoDBClient).Atlas + + auditingReq := &matlas.Auditing{} + + auditingReq.Enabled = pointy.Bool(false) + + _, _, err := conn.Auditing.Configure(ctx, d.Id(), auditingReq) + if err != nil { + return diag.FromErr(fmt.Errorf(errorAuditingUpdate, d.Id(), err)) + } + d.SetId("") return nil diff --git a/mongodbatlas/resource_mongodbatlas_cloud_backup_schedule.go b/mongodbatlas/resource_mongodbatlas_cloud_backup_schedule.go index dd315ec367..00902f0ca0 100644 --- a/mongodbatlas/resource_mongodbatlas_cloud_backup_schedule.go +++ b/mongodbatlas/resource_mongodbatlas_cloud_backup_schedule.go @@ -50,6 +50,35 @@ func resourceMongoDBAtlasCloudBackupSchedule() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "auto_export_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "use_org_and_group_names_in_export_prefix": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "export": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "export_bucket_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "frequency_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, "policy_item_hourly": { Type: schema.TypeList, MaxItems: 1, @@ -273,6 +302,10 @@ func resourceMongoDBAtlasCloudBackupScheduleRead(ctx context.Context, d *schema. return diag.Errorf(errorSnapshotBackupScheduleSetting, "id_policy", clusterName, err) } + if err := d.Set("export", flattenExport(backupPolicy)); err != nil { + return diag.Errorf(errorSnapshotBackupScheduleSetting, "auto_export_enabled", clusterName, err) + } + if err := d.Set("policy_item_hourly", flattenPolicyItem(backupPolicy.Policies[0].PolicyItems, snapshotScheduleHourly)); err != nil { return diag.Errorf(errorSnapshotBackupScheduleSetting, "policy_item_hourly", clusterName, err) } @@ -372,6 +405,7 @@ func cloudBackupScheduleCreateOrUpdate(ctx context.Context, conn *matlas.Client, policy := matlas.Policy{} policyItem := matlas.PolicyItem{} var policiesItem []matlas.PolicyItem + export := matlas.Export{} if v, ok := d.GetOk("policy_item_hourly"); ok { item := v.([]interface{}) @@ -410,6 +444,15 @@ func cloudBackupScheduleCreateOrUpdate(ctx context.Context, conn *matlas.Client, policiesItem = append(policiesItem, policyItem) } + if v, ok := d.GetOk("export"); ok { + item := v.([]interface{}) + itemObj := item[0].(map[string]interface{}) + export.ExportBucketID = itemObj["export_bucket_id"].(string) + export.FrequencyType = itemObj["frequency_type"].(string) + + req.Export = &export + } + policy.ID = resp.Policies[0].ID policy.PolicyItems = policiesItem if len(policiesItem) > 0 { @@ -455,3 +498,15 @@ func flattenPolicyItem(items []matlas.PolicyItem, frequencyType string) []map[st return policyItems } + +func flattenExport(roles *matlas.CloudProviderSnapshotBackupPolicy) []map[string]interface{} { + exportList := make([]map[string]interface{}, 0) + emptyStruct := matlas.CloudProviderSnapshotBackupPolicy{} + if emptyStruct.Export != roles.Export { + exportList = append(exportList, map[string]interface{}{ + "frequency_type": roles.Export.FrequencyType, + "export_bucket_id": roles.Export.ExportBucketID, + }) + } + return exportList +} diff --git a/mongodbatlas/resource_mongodbatlas_cloud_backup_snapshot_export_bucket.go b/mongodbatlas/resource_mongodbatlas_cloud_backup_snapshot_export_bucket.go index 6962ffd04b..d394cbf64e 100644 --- a/mongodbatlas/resource_mongodbatlas_cloud_backup_snapshot_export_bucket.go +++ b/mongodbatlas/resource_mongodbatlas_cloud_backup_snapshot_export_bucket.go @@ -157,7 +157,7 @@ func resourceMongoDBAtlasCloudBackupSnapshotExportBucketImportState(ctx context. d.SetId(encodeStateID(map[string]string{ "project_id": *projectID, - "name": *id, + "id": *id, })) return []*schema.ResourceData{d}, nil diff --git a/mongodbatlas/resource_mongodbatlas_cloud_provider_access.go b/mongodbatlas/resource_mongodbatlas_cloud_provider_access.go index 464304c59a..2943c39308 100644 --- a/mongodbatlas/resource_mongodbatlas_cloud_provider_access.go +++ b/mongodbatlas/resource_mongodbatlas_cloud_provider_access.go @@ -68,6 +68,14 @@ func resourceMongoDBAtlasCloudProviderAccess() *schema.Resource { Computed: true, }, }, + SchemaVersion: 1, + StateUpgraders: []schema.StateUpgrader{ + { + Type: resourceMongoDBAtlasCloudProviderAccessV0().CoreConfigSchema().ImpliedType(), + Upgrade: resourceMongoDBAtlasCloudProviderAccessStateUpgradeV0, + Version: 0, + }, + }, } } @@ -248,3 +256,53 @@ func splitCloudProviderAccessID(id string) (projectID, providerName, roleID stri return } + +func resourceMongoDBAtlasCloudProviderAccessV0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "project_id": { + Type: schema.TypeString, + Required: true, + }, + "provider_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"AWS"}, false), + }, + "atlas_aws_account_arn": { + Type: schema.TypeString, + Computed: true, + }, + "atlas_assumed_role_external_id": { + Type: schema.TypeString, + Computed: true, + }, + "authorized_date": { + Type: schema.TypeString, + Computed: true, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "iam_assumed_role_arn": { + Type: schema.TypeString, + Optional: true, + }, + "role_id": { + Type: schema.TypeString, + Computed: true, + }, + "feature_usages": { + Type: schema.TypeList, + Elem: featureUsagesSchemaV0(), + Computed: true, + }, + }, + } +} + +func resourceMongoDBAtlasCloudProviderAccessStateUpgradeV0(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + rawState["feature_usages"] = []interface{}{map[string]interface{}{}} + return rawState, nil +} diff --git a/mongodbatlas/resource_mongodbatlas_cluster_test.go b/mongodbatlas/resource_mongodbatlas_cluster_test.go index 36ee241944..728fa94947 100644 --- a/mongodbatlas/resource_mongodbatlas_cluster_test.go +++ b/mongodbatlas/resource_mongodbatlas_cluster_test.go @@ -524,10 +524,11 @@ func TestAccResourceMongoDBAtlasCluster_MultiRegion(t *testing.T) { func TestAccResourceMongoDBAtlasCluster_Global(t *testing.T) { var ( - cluster matlas.Cluster - resourceName = "mongodbatlas_cluster.global_cluster" - projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - name = fmt.Sprintf("test-acc-global-%s", acctest.RandString(10)) + cluster matlas.Cluster + resourceSuffix = "global_cluster" + resourceName = fmt.Sprintf("mongodbatlas_cluster.%s", resourceSuffix) + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + name = fmt.Sprintf("test-acc-global-%s", acctest.RandString(10)) ) resource.ParallelTest(t, resource.TestCase{ @@ -536,7 +537,7 @@ func TestAccResourceMongoDBAtlasCluster_Global(t *testing.T) { CheckDestroy: testAccCheckMongoDBAtlasClusterDestroy, Steps: []resource.TestStep{ { - Config: testAccMongoDBAtlasClusterConfigGlobal(projectID, name, "false"), + Config: testAccMongoDBAtlasClusterConfigGlobal(resourceSuffix, projectID, name, "false"), Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasClusterExists(resourceName, &cluster), testAccCheckMongoDBAtlasClusterAttributes(&cluster, name), @@ -1537,9 +1538,9 @@ func testAccMongoDBAtlasClusterConfigMultiRegion(projectID, name, backupEnabled, `, projectID, name, backupEnabled, regionsConfig) } -func testAccMongoDBAtlasClusterConfigGlobal(projectID, name, backupEnabled string) string { +func testAccMongoDBAtlasClusterConfigGlobal(resourceName, projectID, name, backupEnabled string) string { return fmt.Sprintf(` - resource "mongodbatlas_cluster" "global_cluster" { + resource "mongodbatlas_cluster" %q { project_id = "%s" name = "%s" disk_size_gb = 80 @@ -1574,7 +1575,7 @@ func testAccMongoDBAtlasClusterConfigGlobal(projectID, name, backupEnabled strin } } } - `, projectID, name, backupEnabled) + `, resourceName, projectID, name, backupEnabled) } func testAccMongoDBAtlasClusterConfigTenant(projectID, name, instanceSize, diskSize, majorDBVersion string) string { diff --git a/mongodbatlas/resource_mongodbatlas_event_trigger.go b/mongodbatlas/resource_mongodbatlas_event_trigger.go index d429971c24..f3a4f62185 100644 --- a/mongodbatlas/resource_mongodbatlas_event_trigger.go +++ b/mongodbatlas/resource_mongodbatlas_event_trigger.go @@ -196,6 +196,11 @@ func resourceMongoDBAtlasEventTriggers() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "unordered": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, }, } } @@ -282,6 +287,10 @@ func resourceMongoDBAtlasEventTriggersCreate(ctx context.Context, d *schema.Reso eventTriggerReq.EventProcessors = expandTriggerEventProcessorAWSEventBridge(v.([]interface{})) } + if v, ok := d.GetOk("unordered"); ok { + eventTriggerConfig.Unordered = pointy.Bool(v.(bool)) + } + eventTriggerReq.Config = eventTriggerConfig eventResp, _, err := conn.EventTriggers.Create(context.Background(), projectID, appID, eventTriggerReq) @@ -378,6 +387,9 @@ func resourceMongoDBAtlasEventTriggersRead(ctx context.Context, d *schema.Resour if err = d.Set("config_schedule_type", resp.Config.ScheduleType); err != nil { return diag.FromErr(fmt.Errorf(errorEventTriggersSetting, "config_schedule_type", projectID, appID, err)) } + if err = d.Set("unordered", resp.Config.Unordered); err != nil { + return diag.FromErr(fmt.Errorf(errorEventTriggersSetting, "unordered", projectID, appID, err)) + } if err = d.Set("event_processors", flattenTriggerEventProcessorAWSEventBridge(resp.EventProcessors)); err != nil { return diag.FromErr(fmt.Errorf(errorEventTriggersSetting, "event_processors", projectID, appID, err)) } @@ -417,6 +429,7 @@ func resourceMongoDBAtlasEventTriggersUpdate(ctx context.Context, d *schema.Reso eventTriggerConfig.Project = cast.ToStringMap(d.Get("config_project").(string)) eventTriggerConfig.FullDocument = pointy.Bool(d.Get("config_full_document").(bool)) eventTriggerConfig.FullDocumentBeforeChange = pointy.Bool(d.Get("config_full_document_before").(bool)) + eventTriggerConfig.Unordered = pointy.Bool(d.Get("unordered").(bool)) } if typeTrigger == "AUTHENTICATION" { eventTriggerConfig.OperationType = d.Get("config_operation_type").(string) diff --git a/mongodbatlas/resource_mongodbatlas_federated_settings_connected_organization.go b/mongodbatlas/resource_mongodbatlas_federated_settings_connected_organization.go new file mode 100644 index 0000000000..68b2e2917b --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_federated_settings_connected_organization.go @@ -0,0 +1,211 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + "net/http" + "regexp" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/spf13/cast" +) + +func resourceMongoDBAtlasFederatedSettingsOrganizationConfig() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceMongoDBAtlasFederatedSettingsOrganizationConfigRead, + ReadContext: resourceMongoDBAtlasFederatedSettingsOrganizationConfigRead, + UpdateContext: resourceMongoDBAtlasFederatedSettingsOrganizationConfigUpdate, + DeleteContext: resourceMongoDBAtlasFederatedSettingsOrganizationConfigDelete, + Importer: &schema.ResourceImporter{ + StateContext: resourceMongoDBAtlasFederatedSettingsOrganizationConfigImportState, + }, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "org_id": { + Type: schema.TypeString, + Required: true, + }, + "identity_provider_id": { + Type: schema.TypeString, + Required: true, + }, + "domain_allow_list": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "post_auth_role_grants": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "domain_restriction_enabled": { + Type: schema.TypeBool, + Required: true, + }, + }, + } +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + if d.Id() == "" { + d.SetId("") + return nil + } + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + orgID := ids["org_id"] + + federatedSettingsConnectedOrganization, resp, err := conn.FederatedSettings.GetConnectedOrg(context.Background(), federationSettingsID, orgID) + if err != nil { + // case 404 + // deleted in the backend case + if resp != nil && resp.StatusCode == http.StatusNotFound { + d.SetId("") + return nil + } + + return diag.FromErr(fmt.Errorf("error getting federated settings organization config: %s", err)) + } + + if err := d.Set("domain_restriction_enabled", federatedSettingsConnectedOrganization.DomainRestrictionEnabled); err != nil { + return diag.FromErr(fmt.Errorf("error setting domain restriction enabled (%s): %s", d.Id(), err)) + } + + if err := d.Set("domain_allow_list", federatedSettingsConnectedOrganization.DomainAllowList); err != nil { + return diag.FromErr(fmt.Errorf("error setting domain allow list (%s): %s", d.Id(), err)) + } + + if err := d.Set("post_auth_role_grants", federatedSettingsConnectedOrganization.PostAuthRoleGrants); err != nil { + return diag.FromErr(fmt.Errorf("error setting post_auth_role_grants (%s): %s", d.Id(), err)) + } + + d.SetId(encodeStateID(map[string]string{ + "federation_settings_id": federationSettingsID, + "org_id": orgID, + })) + + return nil +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationConfigUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + orgID := ids["org_id"] + + federatedSettingsConnectedOrganizationUpdate, _, err := conn.FederatedSettings.GetConnectedOrg(context.Background(), federationSettingsID, orgID) + if err != nil { + return diag.FromErr(fmt.Errorf("error retreiving federation settings connected organization (%s): %s", federationSettingsID, err)) + } + + if d.HasChange("domain_restriction_enabled") { + domainRestrictionEnabled := d.Get("domain_restriction_enabled").(bool) + federatedSettingsConnectedOrganizationUpdate.DomainRestrictionEnabled = &domainRestrictionEnabled + } + + if d.HasChange("domain_allow_list") { + domainAllowList := d.Get("domain_allow_list") + federatedSettingsConnectedOrganizationUpdate.DomainAllowList = cast.ToStringSlice(domainAllowList) + } + + if d.HasChange("identity_provider_id") { + identityProviderID := d.Get("identity_provider_id").(string) + federatedSettingsConnectedOrganizationUpdate.IdentityProviderID = identityProviderID + } + + if d.HasChange("post_auth_role_grants") { + postAuthRoleGrants := d.Get("post_auth_role_grants") + federatedSettingsConnectedOrganizationUpdate.PostAuthRoleGrants = cast.ToStringSlice(postAuthRoleGrants) + } + + _, _, err = conn.FederatedSettings.UpdateConnectedOrg(ctx, federationSettingsID, orgID, federatedSettingsConnectedOrganizationUpdate) + if err != nil { + return diag.FromErr(fmt.Errorf("error updating federation settings connected organization (%s): %s", federationSettingsID, err)) + } + + return resourceMongoDBAtlasFederatedSettingsOrganizationConfigRead(ctx, d, meta) +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationConfigDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + orgID := ids["org_id"] + + _, err := conn.FederatedSettings.DeleteConnectedOrg(ctx, federationSettingsID, orgID) + if err != nil { + return diag.FromErr(fmt.Errorf("error deleting federation settings connected organization (%s): %s", federationSettingsID, err)) + } + + return nil +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationConfigImportState(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*MongoDBClient).Atlas + federationSettingsID, orgID, err := splitFederatedSettingsOrganizationConfigImportID(d.Id()) + if err != nil { + return nil, err + } + + federatedSettingsConnectedOrganization, _, err := conn.FederatedSettings.GetConnectedOrg(context.Background(), *federationSettingsID, *orgID) + if err != nil { + return nil, fmt.Errorf("couldn't import Organization config (%s) in Federation settings (%s), error: %s", *orgID, *federationSettingsID, err) + } + + if err := d.Set("federation_settings_id", *federationSettingsID); err != nil { + return nil, fmt.Errorf("error setting Organization config in Federation settings (%s): %s", d.Id(), err) + } + + if err := d.Set("domain_restriction_enabled", federatedSettingsConnectedOrganization.DomainRestrictionEnabled); err != nil { + return nil, fmt.Errorf("error setting domain restriction enabled (%s): %s", d.Id(), err) + } + + if err := d.Set("domain_allow_list", federatedSettingsConnectedOrganization.DomainAllowList); err != nil { + return nil, fmt.Errorf("error setting domain allow list (%s): %s", d.Id(), err) + } + + if err := d.Set("org_id", federatedSettingsConnectedOrganization.OrgID); err != nil { + return nil, fmt.Errorf("error setting org id (%s): %s", d.Id(), err) + } + + if err := d.Set("identity_provider_id", federatedSettingsConnectedOrganization.IdentityProviderID); err != nil { + return nil, fmt.Errorf("error setting identity provider id (%s): %s", d.Id(), err) + } + + d.SetId(encodeStateID(map[string]string{ + "federation_settings_id": *federationSettingsID, + "org_id": *orgID, + })) + + return []*schema.ResourceData{d}, nil +} + +func splitFederatedSettingsOrganizationConfigImportID(id string) (federationSettingsID, orgID *string, err error) { + var re = regexp.MustCompile(`(?s)^(.*)-(.*)$`) + parts := re.FindStringSubmatch(id) + + if len(parts) != 3 { + err = errors.New("import format error: to import a Federated Settings Orgnization Config, use the format {federation_settings_id}-{org_id}") + return + } + + federationSettingsID = &parts[1] + orgID = &parts[2] + + return +} diff --git a/mongodbatlas/resource_mongodbatlas_federated_settings_connected_organization_test.go b/mongodbatlas/resource_mongodbatlas_federated_settings_connected_organization_test.go new file mode 100644 index 0000000000..5dd9a6d8f7 --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_federated_settings_connected_organization_test.go @@ -0,0 +1,122 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func TestAccResourceMongoDBAtlasFederatedSettingsOrganizationConfig_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + federatedSettingsIdentityProvider matlas.FederatedSettingsConnectedOrganization + resourceName = "mongodbatlas_federated_settings_org_config.test" + federationSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + idpID = os.Getenv("MONGODB_ATLAS_FEDERATED_IDP_ID") + ) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasFederatedSettingsOrganizationConfig(federationSettingsID, orgID, idpID), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigImportStateIDFunc(resourceName, federationSettingsID, orgID), + ImportState: true, + ImportStateVerify: false, + }, + { + Config: testAccMongoDBAtlasFederatedSettingsOrganizationConfig(federationSettingsID, orgID, idpID), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigImportStateIDFunc(resourceName, federationSettingsID, orgID), + + ImportState: true, + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigRExists(resourceName, &federatedSettingsIdentityProvider), + resource.TestCheckResourceAttr(resourceName, "federation_settings_id", federationSettingsID), + resource.TestCheckResourceAttr(resourceName, "name", "mongodb_federation_test"), + ), + }, + }, + }) +} + +func TestAccResourceMongoDBAtlasFederatedSettingsOrganizationConfig_importBasic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "mongodbatlas_federated_settings_org_config.test" + federationSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + idpID = os.Getenv("MONGODB_ATLAS_FEDERATED_OKTA_IDP_ID") + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + + { + Config: testAccMongoDBAtlasFederatedSettingsOrganizationConfig(federationSettingsID, orgID, idpID), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigImportStateIDFunc(resourceName, federationSettingsID, orgID), + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigRExists(resourceName string, + federatedSettingsIdentityProvider *matlas.FederatedSettingsConnectedOrganization) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + response, _, err := conn.FederatedSettings.GetConnectedOrg(context.Background(), + rs.Primary.Attributes["federation_settings_id"], + rs.Primary.Attributes["org_id"]) + if err == nil { + *federatedSettingsIdentityProvider = *response + return nil + } + + return fmt.Errorf("connected org (%s) does not exist", rs.Primary.Attributes["org_id"]) + } +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationConfigImportStateIDFunc(resourceName, federationSettingsID, orgID string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + ID := encodeStateID(map[string]string{ + "federation_settings_id": federationSettingsID, + "org_id": orgID, + }) + + ids := decodeStateID(ID) + return fmt.Sprintf("%s-%s", ids["federation_settings_id"], ids["org_id"]), nil + } +} + +func testAccMongoDBAtlasFederatedSettingsOrganizationConfig(federationSettingsID, orgID, identityProviderID string) string { + return fmt.Sprintf(` + resource "mongodbatlas_federated_settings_org_config" "test" { + federation_settings_id = "%[1]s" + org_id = "%[2]s" + domain_restriction_enabled = false + domain_allow_list = ["reorganizeyourworld.com"] + identity_provider_id = "%[3]s" + }`, federationSettingsID, orgID, identityProviderID) +} diff --git a/mongodbatlas/resource_mongodbatlas_federated_settings_identity_provider.go b/mongodbatlas/resource_mongodbatlas_federated_settings_identity_provider.go new file mode 100644 index 0000000000..b976d9076e --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_federated_settings_identity_provider.go @@ -0,0 +1,265 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + "net/http" + "regexp" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/spf13/cast" +) + +func resourceMongoDBAtlasFederatedSettingsIdentityProvider() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceMongoDBAtlasFederatedSettingsIdentityProviderRead, + ReadContext: resourceMongoDBAtlasFederatedSettingsIdentityProviderRead, + UpdateContext: resourceMongoDBAtlasFederatedSettingsIdentityProviderUpdate, + DeleteContext: resourceMongoDBAtlasFederatedSettingsIdentityProviderDelete, + Importer: &schema.ResourceImporter{ + StateContext: resourceMongoDBAtlasFederatedSettingsIdentityProviderImportState, + }, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "issuer_uri": { + Type: schema.TypeString, + Required: true, + }, + "request_binding": { + Type: schema.TypeString, + Required: true, + }, + "response_signature_algorithm": { + Type: schema.TypeString, + Required: true, + }, + "associated_domains": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "sso_debug_enabled": { + Type: schema.TypeBool, + Required: true, + }, + "sso_url": { + Type: schema.TypeString, + Required: true, + }, + "status": { + Type: schema.TypeString, + Required: true, + }, + "okta_idp_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceMongoDBAtlasFederatedSettingsIdentityProviderRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + if d.Id() == "" { + d.SetId("") + return nil + } + + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + oktaIdpID := ids["okta_idp_id"] + + federatedSettingsIdentityProvider, resp, err := conn.FederatedSettings.GetIdentityProvider(context.Background(), federationSettingsID, oktaIdpID) + if err != nil { + // case 404 + // deleted in the backend case + if resp != nil && resp.StatusCode == http.StatusNotFound { + d.SetId("") + return nil + } + + return diag.FromErr(fmt.Errorf("error getting federated settings identity provider: %s", err)) + } + + if err := d.Set("sso_debug_enabled", federatedSettingsIdentityProvider.SsoDebugEnabled); err != nil { + return diag.FromErr(fmt.Errorf("error setting sso debug enabled (%s): %s", d.Id(), err)) + } + + if err := d.Set("associated_domains", federatedSettingsIdentityProvider.AssociatedDomains); err != nil { + return diag.FromErr(fmt.Errorf("error setting associated domains list (%s): %s", d.Id(), err)) + } + + if err := d.Set("okta_idp_id", federatedSettingsIdentityProvider.OktaIdpID); err != nil { + return diag.FromErr(fmt.Errorf("error setting OktaIdpID (%s): %s", d.Id(), err)) + } + + if err := d.Set("status", federatedSettingsIdentityProvider.Status); err != nil { + return diag.FromErr(fmt.Errorf("error setting Status (%s): %s", d.Id(), err)) + } + + if err := d.Set("issuer_uri", federatedSettingsIdentityProvider.IssuerURI); err != nil { + return diag.FromErr(fmt.Errorf("error setting issuer uri (%s): %s", d.Id(), err)) + } + + if err := d.Set("request_binding", federatedSettingsIdentityProvider.RequestBinding); err != nil { + return diag.FromErr(fmt.Errorf("error setting request binding (%s): %s", d.Id(), err)) + } + + if err := d.Set("response_signature_algorithm", federatedSettingsIdentityProvider.ResponseSignatureAlgorithm); err != nil { + return diag.FromErr(fmt.Errorf("error setting response signature algorithm (%s): %s", d.Id(), err)) + } + + if err := d.Set("sso_url", federatedSettingsIdentityProvider.SsoURL); err != nil { + return diag.FromErr(fmt.Errorf("error setting sso url (%s): %s", d.Id(), err)) + } + + d.SetId(encodeStateID(map[string]string{ + "federation_settings_id": federationSettingsID, + "okta_idp_id": oktaIdpID, + })) + + return nil +} + +func resourceMongoDBAtlasFederatedSettingsIdentityProviderUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + oktaIdpID := ids["okta_idp_id"] + + federatedSettingsIdentityProviderUpdate, _, err := conn.FederatedSettings.GetIdentityProvider(context.Background(), federationSettingsID, oktaIdpID) + if err != nil { + return diag.FromErr(fmt.Errorf("error retreiving federation settings identity provider (%s): %s", federationSettingsID, err)) + } + + if d.HasChange("sso_debug_enabled") { + ssoDebugEnabled := d.Get("sso_debug_enabled").(bool) + federatedSettingsIdentityProviderUpdate.SsoDebugEnabled = &ssoDebugEnabled + } + + if d.HasChange("associated_domains") { + associatedDomains := d.Get("associated_domains") + federatedSettingsIdentityProviderUpdate.AssociatedDomains = cast.ToStringSlice(associatedDomains) + } + + if d.HasChange("name") { + identityName := d.Get("name").(string) + federatedSettingsIdentityProviderUpdate.DisplayName = identityName + } + + if d.HasChange("status") { + status := d.Get("status").(string) + federatedSettingsIdentityProviderUpdate.Status = status + } + + if d.HasChange("issuer_uri") { + status := d.Get("issuer_uri").(string) + federatedSettingsIdentityProviderUpdate.IssuerURI = status + } + + if d.HasChange("request_binding") { + status := d.Get("request_binding").(string) + federatedSettingsIdentityProviderUpdate.RequestBinding = status + } + + if d.HasChange("response_signature_algorithm") { + status := d.Get("response_signature_algorithm").(string) + federatedSettingsIdentityProviderUpdate.ResponseSignatureAlgorithm = status + } + + if d.HasChange("sso_url") { + status := d.Get("sso_url").(string) + federatedSettingsIdentityProviderUpdate.SsoURL = status + } + + federatedSettingsIdentityProviderUpdate.PemFileInfo = nil + + _, _, err = conn.FederatedSettings.UpdateIdentityProvider(ctx, federationSettingsID, oktaIdpID, federatedSettingsIdentityProviderUpdate) + if err != nil { + return diag.FromErr(fmt.Errorf("error updating federation settings identity provider (%s): %s", federationSettingsID, err)) + } + + return resourceMongoDBAtlasFederatedSettingsIdentityProviderRead(ctx, d, meta) +} + +func resourceMongoDBAtlasFederatedSettingsIdentityProviderDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId("") + return nil +} + +func resourceMongoDBAtlasFederatedSettingsIdentityProviderImportState(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*MongoDBClient).Atlas + federationSettingsID, oktaIdpID, err := splitFederatedSettingsIdentityProviderImportID(d.Id()) + if err != nil { + return nil, err + } + + federatedSettingsIdentityProvider, _, err := conn.FederatedSettings.GetIdentityProvider(context.Background(), *federationSettingsID, *oktaIdpID) + if err != nil { + return nil, fmt.Errorf("couldn't import Organization config (%s) in Federation settings (%s), error: %s", *oktaIdpID, *federationSettingsID, err) + } + + if err := d.Set("federation_settings_id", *federationSettingsID); err != nil { + return nil, fmt.Errorf("error setting Identity Provider in Federation settings (%s): %s", d.Id(), err) + } + + if err := d.Set("sso_debug_enabled", federatedSettingsIdentityProvider.SsoDebugEnabled); err != nil { + return nil, fmt.Errorf("error setting sso debug enabled (%s): %s", d.Id(), err) + } + + if err := d.Set("associated_domains", federatedSettingsIdentityProvider.AssociatedDomains); err != nil { + return nil, fmt.Errorf("error setting associaed domains list (%s): %s", d.Id(), err) + } + + if err := d.Set("issuer_uri", federatedSettingsIdentityProvider.IssuerURI); err != nil { + return nil, fmt.Errorf("error setting issuer uri (%s): %s", d.Id(), err) + } + + if err := d.Set("request_binding", federatedSettingsIdentityProvider.RequestBinding); err != nil { + return nil, fmt.Errorf("error setting request binding (%s): %s", d.Id(), err) + } + + if err := d.Set("response_signature_algorithm", federatedSettingsIdentityProvider.ResponseSignatureAlgorithm); err != nil { + return nil, fmt.Errorf("error setting response signature algorithm (%s): %s", d.Id(), err) + } + + if err := d.Set("sso_url", federatedSettingsIdentityProvider.SsoURL); err != nil { + return nil, fmt.Errorf("error setting sso url (%s): %s", d.Id(), err) + } + + d.SetId(encodeStateID(map[string]string{ + "federation_settings_id": *federationSettingsID, + "okta_idp_id": *oktaIdpID, + })) + + return []*schema.ResourceData{d}, nil +} + +func splitFederatedSettingsIdentityProviderImportID(id string) (federationSettingsID, oktaIdpID *string, err error) { + var re = regexp.MustCompile(`(?s)^(.*)-(.*)$`) + parts := re.FindStringSubmatch(id) + + if len(parts) != 3 { + err = errors.New("import format error: to import a Federated SettingsIdentity Provider, use the format {federation_settings_id}-{okta_idp_id}") + return + } + + federationSettingsID = &parts[1] + oktaIdpID = &parts[2] + + return +} diff --git a/mongodbatlas/resource_mongodbatlas_federated_settings_identity_provider_test.go b/mongodbatlas/resource_mongodbatlas_federated_settings_identity_provider_test.go new file mode 100644 index 0000000000..e704b4c5f6 --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_federated_settings_identity_provider_test.go @@ -0,0 +1,128 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func TestAccResourceMongoDBAtlasFederatedSettingsIdentityProvider_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + federatedSettingsIdentityProvider matlas.FederatedSettingsIdentityProvider + resourceName = "mongodbatlas_federated_settings_identity_provider.test" + federationSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + idpID = os.Getenv("MONGODB_ATLAS_FEDERATED_OKTA_IDP_ID") + ssoURL = os.Getenv("MONGODB_ATLAS_FEDERATED_SSO_URL") + issuerURI = os.Getenv("MONGODB_ATLAS_FEDERATED_ISSUER_URI") + ) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasFederatedSettingsIdentityProviderConfig(federationSettingsID, ssoURL, issuerURI), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasFederatedSettingsIdentityProviderImportStateIDFunc(resourceName, federationSettingsID, idpID), + ImportState: true, + ImportStateVerify: false, + }, + { + Config: testAccMongoDBAtlasFederatedSettingsIdentityProviderConfig(federationSettingsID, ssoURL, issuerURI), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasFederatedSettingsIdentityProviderImportStateIDFunc(resourceName, federationSettingsID, idpID), + + ImportState: true, + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsIdentityProviderExists(resourceName, &federatedSettingsIdentityProvider, idpID), + resource.TestCheckResourceAttr(resourceName, "federation_settings_id", federationSettingsID), + resource.TestCheckResourceAttr(resourceName, "name", "mongodb_federation_test"), + ), + }, + }, + }) +} + +func TestAccResourceMongoDBAtlasFederatedSettingsIdentityProvider_importBasic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "mongodbatlas_federated_settings_identity_provider.test" + federationSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + idpID = os.Getenv("MONGODB_ATLAS_FEDERATED_OKTA_IDP_ID") + ssoURL = os.Getenv("MONGODB_ATLAS_FEDERATED_SSO_URL") + issuerURI = os.Getenv("MONGODB_ATLAS_FEDERATED_ISSUER_URI") + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + + { + Config: testAccMongoDBAtlasFederatedSettingsIdentityProviderConfig(federationSettingsID, ssoURL, issuerURI), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasFederatedSettingsIdentityProviderImportStateIDFunc(resourceName, federationSettingsID, idpID), + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckMongoDBAtlasFederatedSettingsIdentityProviderExists(resourceName string, + federatedSettingsIdentityProvider *matlas.FederatedSettingsIdentityProvider, idpID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + response, _, err := conn.FederatedSettings.GetIdentityProvider(context.Background(), + rs.Primary.Attributes["federation_settings_id"], + idpID) + if err == nil { + *federatedSettingsIdentityProvider = *response + return nil + } + + return fmt.Errorf("identity provider (%s) does not exist", idpID) + } +} + +func testAccCheckMongoDBAtlasFederatedSettingsIdentityProviderImportStateIDFunc(resourceName, federationSettingsID, idpID string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + ID := encodeStateID(map[string]string{ + "federation_settings_id": federationSettingsID, + "okta_idp_id": idpID, + }) + + ids := decodeStateID(ID) + return fmt.Sprintf("%s-%s", ids["federation_settings_id"], ids["okta_idp_id"]), nil + } +} + +func testAccMongoDBAtlasFederatedSettingsIdentityProviderConfig(federationSettingsID, ssoURL, issuerURI string) string { + return fmt.Sprintf(` + resource "mongodbatlas_federated_settings_identity_provider" "test" { + federation_settings_id = "%[1]s" + name = "mongodb_federation_test" + associated_domains = ["reorganizeyourworld.com"] + sso_debug_enabled = true + status = "ACTIVE" + sso_url = "%[2]s" + issuer_uri = "%[3]s" + request_binding = "HTTP-POST" + response_signature_algorithm = "SHA-256" + }`, federationSettingsID, ssoURL, issuerURI) +} diff --git a/mongodbatlas/resource_mongodbatlas_federated_settings_organization_role_mapping.go b/mongodbatlas/resource_mongodbatlas_federated_settings_organization_role_mapping.go new file mode 100644 index 0000000000..847bb59394 --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_federated_settings_organization_role_mapping.go @@ -0,0 +1,367 @@ +package mongodbatlas + +import ( + "context" + "errors" + "fmt" + "net/http" + "regexp" + "sort" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func resourceMongoDBAtlasFederatedSettingsOrganizationRoleMapping() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingCreate, + ReadContext: resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingRead, + UpdateContext: resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingUpdate, + DeleteContext: resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingDelete, + Importer: &schema.ResourceImporter{ + StateContext: resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingImportState, + }, + Schema: map[string]*schema.Schema{ + "federation_settings_id": { + Type: schema.TypeString, + Required: true, + }, + "org_id": { + Type: schema.TypeString, + Required: true, + }, + + "external_group_name": { + Type: schema.TypeString, + Required: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "role_assignments": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "group_id": { + Type: schema.TypeString, + Optional: true, + }, + "org_id": { + Type: schema.TypeString, + Optional: true, + }, + "roles": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + } +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + orgID := ids["org_id"] + roleMappingID := ids["role_mapping_id"] + + federatedSettingsOrganizationRoleMapping, resp, err := conn.FederatedSettings.GetRoleMapping(context.Background(), federationSettingsID, orgID, roleMappingID) + + if err != nil { + // case 404 + // deleted in the backend case + if resp != nil && resp.StatusCode == http.StatusNotFound { + d.SetId("") + return nil + } + + return diag.FromErr(fmt.Errorf("error getting federated settings organization config: %s", err)) + } + + if err := d.Set("external_group_name", federatedSettingsOrganizationRoleMapping.ExternalGroupName); err != nil { + return diag.FromErr(fmt.Errorf("error setting external group name (%s): %s", d.Id(), err)) + } + + if err := d.Set("role_assignments", flattenRoleAssignmentsSpecial(federatedSettingsOrganizationRoleMapping.RoleAssignments)); err != nil { + return diag.FromErr(fmt.Errorf("error setting role_assignments (%s): %s", d.Id(), err)) + } + + d.SetId(encodeStateID(map[string]string{ + "federation_settings_id": federationSettingsID, + "org_id": orgID, + "role_mapping_id": roleMappingID, + })) + + return nil +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + federationSettingsID, federationSettingsIDOk := d.GetOk("federation_settings_id") + + if !federationSettingsIDOk { + return diag.FromErr(errors.New("federation_settings_id must be configured")) + } + + orgID, orgIDOk := d.GetOk("org_id") + + if !orgIDOk { + return diag.FromErr(errors.New("org_id must be configured")) + } + + externalGroupName := d.Get("external_group_name").(string) + + body := &matlas.FederatedSettingsOrganizationRoleMapping{} + + ra := []*matlas.RoleAssignments{} + + body.ExternalGroupName = externalGroupName + roleAssignments := expandRoleAssignments(d) + + for i := range roleAssignments { + ra = append(ra, &roleAssignments[i]) + } + + body.RoleAssignments = ra + + federatedSettingsOrganizationRoleMapping, resp, err := conn.FederatedSettings.CreateRoleMapping(context.Background(), federationSettingsID.(string), orgID.(string), body) + if err != nil { + // case 404 + // deleted in the backend case + if resp != nil && resp.StatusCode == http.StatusNotFound { + d.SetId("") + return nil + } + + return diag.FromErr(fmt.Errorf("error getting federated settings organization config: %s", err)) + } + + d.SetId(encodeStateID(map[string]string{ + "federation_settings_id": federationSettingsID.(string), + "org_id": orgID.(string), + "role_mapping_id": federatedSettingsOrganizationRoleMapping.ID, + })) + + return resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingRead(ctx, d, meta) +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + orgID := ids["org_id"] + roleMappingID := ids["role_mapping_id"] + + federatedSettingsOrganizationRoleMappingUpdate, _, err := conn.FederatedSettings.GetRoleMapping(context.Background(), federationSettingsID, orgID, roleMappingID) + if err != nil { + return diag.FromErr(fmt.Errorf("error retreiving federation settings connected organization (%s): %s", federationSettingsID, err)) + } + + if d.HasChange("external_group_name") { + externalGroupName := d.Get("external_group_name").(string) + federatedSettingsOrganizationRoleMappingUpdate.ExternalGroupName = externalGroupName + } + + if d.HasChange("role_assignments") { + federatedSettingsOrganizationRoleMappingUpdate.RoleAssignments = nil + + ra := []*matlas.RoleAssignments{} + + roleAssignments := expandRoleAssignments(d) + + for i := range roleAssignments { + ra = append(ra, &roleAssignments[i]) + } + + federatedSettingsOrganizationRoleMappingUpdate.RoleAssignments = ra + } + _, _, err = conn.FederatedSettings.UpdateRoleMapping(ctx, federationSettingsID, orgID, roleMappingID, federatedSettingsOrganizationRoleMappingUpdate) + if err != nil { + return diag.FromErr(fmt.Errorf("error updating federation settings connected organization (%s): %s", federationSettingsID, err)) + } + + return resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingRead(ctx, d, meta) +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + // Get client connection. + conn := meta.(*MongoDBClient).Atlas + ids := decodeStateID(d.Id()) + federationSettingsID := ids["federation_settings_id"] + orgID := ids["org_id"] + roleMappingID := ids["role_mapping_id"] + + _, err := conn.FederatedSettings.DeleteRoleMapping(ctx, federationSettingsID, orgID, roleMappingID) + if err != nil { + return diag.FromErr(fmt.Errorf("error deleting federation settings connected organization (%s): %s", federationSettingsID, err)) + } + + return nil +} + +func resourceMongoDBAtlasFederatedSettingsOrganizationRoleMappingImportState(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*MongoDBClient).Atlas + + federationSettingsID, orgID, roleMappingID, err := splitFederatedSettingsOrganizationRoleMappingImportID(d.Id()) + if err != nil { + return nil, err + } + + federatedSettingsOrganizationRoleMapping, _, err := conn.FederatedSettings.GetRoleMapping(context.Background(), *federationSettingsID, *orgID, *roleMappingID) + if err != nil { + return nil, fmt.Errorf("couldn't import Role Mappings (%s) in Federation settings (%s), error: %s", *roleMappingID, *federationSettingsID, err) + } + + if err := d.Set("federation_settings_id", *federationSettingsID); err != nil { + return nil, fmt.Errorf("error setting role mapping in Federation settings (%s): %s", d.Id(), err) + } + + if err := d.Set("org_id", *orgID); err != nil { + return nil, fmt.Errorf("error setting role mapping in Federation settings (%s): %s", d.Id(), err) + } + + if err := d.Set("role_assignments", flattenRoleAssignmentsSpecial(federatedSettingsOrganizationRoleMapping.RoleAssignments)); err != nil { + return nil, fmt.Errorf("error setting role_assignments (%s): %s", d.Id(), err) + } + + d.SetId(encodeStateID(map[string]string{ + "federation_settings_id": *federationSettingsID, + "org_id": *orgID, + "role_mapping_id": *roleMappingID, + })) + + return []*schema.ResourceData{d}, nil +} + +func splitFederatedSettingsOrganizationRoleMappingImportID(id string) (federationSettingsID, orgID, roleMappingID *string, err error) { + var re = regexp.MustCompile(`(?s)^(.*)-(.*)-(.*)$`) + parts := re.FindStringSubmatch(id) + + if len(parts) != 4 { + err = errors.New("import format error: to import a Federated Settings Role Mappings, use the format {federation_settings_id}-{org_id}-{role_mapping_id}") + return + } + + federationSettingsID = &parts[1] + orgID = &parts[2] + roleMappingID = &parts[3] + + return +} + +type roleAssignmentsByFields []matlas.RoleAssignments + +func (ra roleAssignmentsByFields) Len() int { return len(ra) } +func (ra roleAssignmentsByFields) Swap(i, j int) { ra[i], ra[j] = ra[j], ra[i] } + +func (ra roleAssignmentsByFields) Less(i, j int) bool { + compareVal := strings.Compare(ra[i].OrgID, ra[j].OrgID) + + if compareVal != 0 { + return compareVal < 0 + } + + compareVal = strings.Compare(ra[i].GroupID, ra[j].GroupID) + + if compareVal != 0 { + return compareVal < 0 + } + + return ra[i].Role < ra[j].Role +} + +type roleAssignmentRefsByFields []*matlas.RoleAssignments + +func (ra roleAssignmentRefsByFields) Len() int { return len(ra) } +func (ra roleAssignmentRefsByFields) Swap(i, j int) { ra[i], ra[j] = ra[j], ra[i] } + +func (ra roleAssignmentRefsByFields) Less(i, j int) bool { + compareVal := strings.Compare(ra[i].OrgID, ra[j].OrgID) + + if compareVal != 0 { + return compareVal < 0 + } + + compareVal = strings.Compare(ra[i].GroupID, ra[j].GroupID) + + if compareVal != 0 { + return compareVal < 0 + } + + return ra[i].Role < ra[j].Role +} + +func expandRoleAssignments(d *schema.ResourceData) []matlas.RoleAssignments { + var roleAssignmentsReturn []matlas.RoleAssignments + + if v, ok := d.GetOk("role_assignments"); ok { + if rs := v.(*schema.Set); rs.Len() > 0 { + roleAssignments := []matlas.RoleAssignments{} + roleAssignment := matlas.RoleAssignments{} + + for _, r := range rs.List() { + roleMap := r.(map[string]interface{}) + + for _, role := range roleMap["roles"].(*schema.Set).List() { + roleAssignment.OrgID = roleMap["org_id"].(string) + roleAssignment.GroupID = roleMap["group_id"].(string) + roleAssignment.Role = role.(string) + roleAssignments = append(roleAssignments, roleAssignment) + } + roleAssignmentsReturn = roleAssignments + } + } + } + + sort.Sort(roleAssignmentsByFields(roleAssignmentsReturn)) + + return roleAssignmentsReturn +} + +func flattenRoleAssignmentsSpecial(roleAssignments []*matlas.RoleAssignments) []map[string]interface{} { + if len(roleAssignments) == 0 { + return nil + } + + sort.Sort(roleAssignmentRefsByFields(roleAssignments)) + + var flattenedRoleAssignments []map[string]interface{} + var roleAssignment = map[string]interface{}{ + "group_id": roleAssignments[0].GroupID, + "org_id": roleAssignments[0].OrgID, + "roles": []string{}, + } + + for _, row := range roleAssignments { + if (roleAssignment["org_id"] != "" && roleAssignment["org_id"] != row.OrgID) || + (roleAssignment["group_id"] != "" && roleAssignment["group_id"] != row.GroupID) { + flattenedRoleAssignments = append(flattenedRoleAssignments, roleAssignment) + + roleAssignment = map[string]interface{}{ + "group_id": row.GroupID, + "org_id": row.OrgID, + "roles": []string{}, + } + } + + roleAssignment["roles"] = append(roleAssignment["roles"].([]string), row.Role) + } + + flattenedRoleAssignments = append(flattenedRoleAssignments, roleAssignment) + + return flattenedRoleAssignments +} diff --git a/mongodbatlas/resource_mongodbatlas_federated_settings_organization_role_mapping_test.go b/mongodbatlas/resource_mongodbatlas_federated_settings_organization_role_mapping_test.go new file mode 100644 index 0000000000..283ba2251a --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_federated_settings_organization_role_mapping_test.go @@ -0,0 +1,145 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func TestAccResourceMongoDBAtlasFederatedSettingsOrganizationRoleMapping_basic(t *testing.T) { + SkipTestExtCred(t) + var ( + federatedSettingsOrganizationRoleMapping matlas.FederatedSettingsOrganizationRoleMapping + resourceName = "mongodbatlas_federated_settings_org_role_mapping.test" + federationSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + groupID = os.Getenv("MONGODB_ATLAS_FEDERATED_GROUP_ID") + ) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasFederatedSettingsOrganizationRoleMappingConfig(federationSettingsID, orgID, groupID), + + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingExists(resourceName, &federatedSettingsOrganizationRoleMapping), + resource.TestCheckResourceAttr(resourceName, "federation_settings_id", federationSettingsID), + resource.TestCheckResourceAttr(resourceName, "org_id", orgID), + resource.TestCheckResourceAttr(resourceName, "external_group_name", "newtestgroup"), + ), + }, + }, + }) +} + +func TestAccResourceMongoDBAtlasFederatedSettingsOrganizationRoleMapping_importBasic(t *testing.T) { + SkipTestExtCred(t) + var ( + resourceName = "mongodbatlas_federated_settings_org_role_mapping.test" + federationSettingsID = os.Getenv("MONGODB_ATLAS_FEDERATION_SETTINGS_ID") + orgID = os.Getenv("MONGODB_ATLAS_FEDERATED_ORG_ID") + groupID = os.Getenv("MONGODB_ATLAS_FEDERATED_GROUP_ID") + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { checkFederatedSettings(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingDestroy, + Steps: []resource.TestStep{ + + { + Config: testAccMongoDBAtlasFederatedSettingsOrganizationRoleMappingConfig(federationSettingsID, orgID, groupID), + ResourceName: resourceName, + ImportStateIdFunc: testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingImportStateIDFunc(resourceName), + ImportState: false, + ImportStateVerify: false, + }, + }, + }) +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingExists(resourceName string, + federatedSettingsOrganizationRoleMapping *matlas.FederatedSettingsOrganizationRoleMapping) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + response, _, err := conn.FederatedSettings.GetRoleMapping(context.Background(), + rs.Primary.Attributes["federation_settings_id"], + rs.Primary.Attributes["org_id"], + rs.Primary.Attributes["role_mapping_id"]) + if err == nil { + *federatedSettingsOrganizationRoleMapping = *response + + return nil + } + + return fmt.Errorf("role mapping (%s) does not exist", rs.Primary.Attributes["role_mapping_id"]) + } +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingDestroy(state *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + for _, rs := range state.RootModule().Resources { + if rs.Type != "mongodbatlas_federated_settings_org_role_mapping" { + continue + } + + ids := decodeStateID(rs.Primary.ID) + + roleMapping, _, err := conn.FederatedSettings.GetRoleMapping(context.Background(), ids["federation_settings_id"], ids["org_id"], ids["role_mapping_id"]) + if err == nil && roleMapping != nil { + return fmt.Errorf("role mapping (%s) still exists", ids["okta_idp_id"]) + } + } + + return nil +} + +func testAccCheckMongoDBAtlasFederatedSettingsOrganizationRoleMappingImportStateIDFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("not found: %s", resourceName) + } + + ids := decodeStateID(rs.Primary.ID) + + return fmt.Sprintf("%s-%s-%s", ids["federation_settings_id"], ids["org_id"], ids["role_mapping_id"]), nil + } +} + +func testAccMongoDBAtlasFederatedSettingsOrganizationRoleMappingConfig(federationSettingsID, orgID, groupID string) string { + return fmt.Sprintf(` + resource "mongodbatlas_federated_settings_org_role_mapping" "test" { + federation_settings_id = "%[1]s" + org_id = "%[2]s" + external_group_name = "newtestgroup" + role_assignments { + org_id = "%[2]s" + roles = ["ORG_MEMBER","ORG_GROUP_CREATOR"] + } + + role_assignments { + group_id = "%[3]s" + roles = ["GROUP_OWNER","GROUP_DATA_ACCESS_ADMIN","GROUP_SEARCH_INDEX_EDITOR","GROUP_DATA_ACCESS_READ_ONLY"] + } + + }`, federationSettingsID, orgID, groupID) +} diff --git a/mongodbatlas/resource_mongodbatlas_private_endpoint_regional_mode.go b/mongodbatlas/resource_mongodbatlas_private_endpoint_regional_mode.go new file mode 100644 index 0000000000..b0cf358eb8 --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_private_endpoint_regional_mode.go @@ -0,0 +1,190 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "log" + "net/http" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +const ( + errorPrivateEndpointRegionalModeRead = "error reading MongoDB Group `%s Private Endpoints Regional Mode: %s" + errorPrivateEndpointRegionalModeSetting = "error setting `%s` on MongoDB Group `%s` Private Endpoints Regional Mode: %s" + errorPrivateEndpointRegionalModeUpdate = "error updating MongoDB Group `%s` Private Endpoints Regional Mode: %s" +) + +func resourceMongoDBAtlasPrivateEndpointRegionalMode() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceMongoDBAtlasPrivateEndpointRegionalModeCreate, + ReadContext: resourceMongoDBAtlasPrivateEndpointRegionalModeRead, + UpdateContext: resourceMongoDBAtlasPrivateEndpointRegionalModeUpdate, + DeleteContext: resourceMongoDBAtlasPrivateEndpointRegionalModeDelete, + Importer: &schema.ResourceImporter{ + StateContext: resourceMongoDBAtlasPrivateEndpointRegionalModeImportState, + }, + Schema: map[string]*schema.Schema{ + "project_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + }, + } +} + +func resourceMongoDBAtlasPrivateEndpointRegionalModeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId(d.Get("project_id").(string)) + err := resourceMongoDBAtlasPrivateEndpointRegionalModeUpdate(ctx, d, meta) + + if err != nil { + return err + } + + return resourceMongoDBAtlasPrivateEndpointRegionalModeRead(ctx, d, meta) +} + +func resourceMongoDBAtlasPrivateEndpointRegionalModeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*MongoDBClient).Atlas + + projectID := d.Id() + + setting, resp, err := conn.PrivateEndpoints.GetRegionalizedPrivateEndpointSetting(context.Background(), projectID) + if err != nil { + if resp != nil && resp.StatusCode == http.StatusNotFound { + d.SetId("") + return nil + } + + return diag.Errorf(errorPrivateEndpointRegionalModeRead, projectID, err) + } + + if err := d.Set("enabled", setting.Enabled); err != nil { + return diag.Errorf(errorPrivateEndpointRegionalModeSetting, "enabled", projectID, err) + } + + return nil +} + +func resourceMongoDBAtlasPrivateEndpointRegionalModeUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*MongoDBClient).Atlas + + projectID := d.Id() + enabled := d.Get("enabled").(bool) + + _, resp, err := conn.PrivateEndpoints.UpdateRegionalizedPrivateEndpointSetting(ctx, projectID, enabled) + if err != nil { + if resp != nil && resp.Response.StatusCode == 404 { + return nil + } + + return diag.Errorf(errorPrivateEndpointRegionalModeUpdate, projectID, err) + } + + log.Println("[INFO] Waiting for MongoDB Clusters' Private Endpoints to be updated") + + stateConf := &resource.StateChangeConf{ + Pending: []string{"PENDING", "REPEATING"}, + Target: []string{"APPLIED"}, + Refresh: resourcePrivateEndpointRegionalModeRefreshFunc(ctx, conn, projectID), + Timeout: 1 * time.Hour, + MinTimeout: 5 * time.Second, + Delay: 3 * time.Second, + } + // Wait, catching any errors + _, err = stateConf.WaitForStateContext(ctx) + if err != nil { + return diag.Errorf(errorPrivateEndpointRegionalModeUpdate, projectID, err) + } + + return nil +} + +func resourceMongoDBAtlasPrivateEndpointRegionalModeDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + if err := d.Set("enabled", false); err == nil { + resourceMongoDBAtlasPrivateEndpointRegionalModeUpdate(ctx, d, meta) + } else { + log.Printf(errorPrivateEndpointRegionalModeSetting, "enabled", d.Id(), err) + } + + d.SetId("") + + return nil +} + +func resourceMongoDBAtlasPrivateEndpointRegionalModeImportState(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*MongoDBClient).Atlas + projectID := d.Id() + + setting, _, err := conn.PrivateEndpoints.GetRegionalizedPrivateEndpointSetting(ctx, projectID) + if err != nil { + return nil, fmt.Errorf("couldn't import Private Endpoint Regional Mode for project %s error: %s", projectID, err) + } + + if err := d.Set("project_id", projectID); err != nil { + log.Printf(errorPrivateEndpointRegionalModeSetting, "project_id", projectID, err) + } + + if err := d.Set("enabled", setting.Enabled); err != nil { + log.Printf(errorPrivateEndpointRegionalModeSetting, "enabled", projectID, err) + } + + d.SetId(projectID) + + return []*schema.ResourceData{d}, nil +} + +func resourcePrivateEndpointRegionalModeRefreshFunc(ctx context.Context, client *matlas.Client, projectID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + clusters, resp, err := client.Clusters.List(ctx, projectID, nil) + + if err != nil { + // For our purposes, no clusters is equivalent to all changes having been APPLIED + if resp != nil && resp.StatusCode == http.StatusNotFound { + return "", "APPLIED", nil + } + + return nil, "REPEATING", err + } + + for i := range clusters { + if clusters[i].StateName == "UPDATING" { + return clusters, "PENDING", nil + } + + s, resp, err := client.Clusters.Status(ctx, projectID, clusters[i].Name) + + if err != nil && strings.Contains(err.Error(), "reset by peer") { + return nil, "REPEATING", nil + } + + if err != nil { + if resp.StatusCode == 404 { + // The cluster no longer exists, consider this equivalent to status APPLIED + continue + } + if resp.StatusCode == 503 { + return "", "PENDING", nil + } + return nil, "REPEATING", err + } + + if s.ChangeStatus == matlas.ChangeStatusPending { + return clusters, "PENDING", nil + } + } + + // If all clusters were properly read, and none are PENDING, all changes have been APPLIED. + return clusters, "APPLIED", nil + } +} diff --git a/mongodbatlas/resource_mongodbatlas_private_endpoint_regional_mode_test.go b/mongodbatlas/resource_mongodbatlas_private_endpoint_regional_mode_test.go new file mode 100644 index 0000000000..3eaf62e012 --- /dev/null +++ b/mongodbatlas/resource_mongodbatlas_private_endpoint_regional_mode_test.go @@ -0,0 +1,194 @@ +package mongodbatlas + +import ( + "context" + "fmt" + "os" + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + matlas "go.mongodb.org/atlas/mongodbatlas" +) + +func TestAccResourceMongoDBAtlasPrivateEndpointRegionalMode_basic(t *testing.T) { + var ( + endpointResourceSuffix = "atlasple" + resourceSuffix = "atlasrm" + resourceName = fmt.Sprintf("mongodbatlas_private_endpoint_regional_mode.%s", resourceSuffix) + + awsAccessKey = os.Getenv("AWS_ACCESS_KEY_ID") + awsSecretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") + + projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + providerName = "AWS" + region = os.Getenv("AWS_REGION") + + clusterName = fmt.Sprintf("test-acc-global-%s", acctest.RandString(10)) + ) + + endpointResources := testAccMongoDBAtlasPrivateLinkEndpointServiceConfigUnmanagedAWS( + awsAccessKey, awsSecretKey, projectID, providerName, region, endpointResourceSuffix, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckMongoDBAtlasPrivateEndpointRegionalModeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasPrivateEndpointRegionalModeConfig(resourceSuffix, projectID, clusterName, endpointResources, endpointResourceSuffix, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasPrivateEndpointRegionalModeExists(resourceName), + testAccCheckMongoDBAtlasPrivateEndpointRegionalModeClustersUpToDate(projectID, clusterName), + resource.TestCheckResourceAttrSet(resourceName, "project_id"), + resource.TestCheckResourceAttrSet(resourceName, "enabled"), + resource.TestCheckResourceAttr(resourceName, "enabled", "false"), + ), + }, + { + Config: testAccMongoDBAtlasPrivateEndpointRegionalModeConfig(resourceSuffix, projectID, clusterName, endpointResources, endpointResourceSuffix, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasPrivateEndpointRegionalModeExists(resourceName), + ), + }, + { + Config: testAccMongoDBAtlasPrivateEndpointRegionalModeConfig(resourceSuffix, projectID, clusterName, endpointResources, endpointResourceSuffix, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasPrivateEndpointRegionalModeExists(resourceName), + testAccCheckMongoDBAtlasPrivateEndpointRegionalModeClustersUpToDate(projectID, clusterName), + resource.TestCheckResourceAttrSet(resourceName, "project_id"), + resource.TestCheckResourceAttrSet(resourceName, "enabled"), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + ), + }, + }, + }) +} + +func testAccMongoDBAtlasPrivateEndpointRegionalModeClusterData(clusterResourceName, regionalModeResourceName, privateLinkResourceName string) string { + return fmt.Sprintf(` + data "mongodbatlas_cluster" %[1]q { + project_id = mongodbatlas_cluster.%[1]s.project_id + name = mongodbatlas_cluster.%[1]s.name + depends_on = [ + mongodbatlas_privatelink_endpoint_service.%[3]s, + mongodbatlas_private_endpoint_regional_mode.%[2]s + ] + } + `, clusterResourceName, regionalModeResourceName, privateLinkResourceName) +} + +func testAccMongoDBAtlasPrivateEndpointRegionalModeConfig(resourceName, projectID, clusterName, endpointResources, endpointResourceName string, enabled bool) string { + clusterResourceName := "global_cluster" + clusterResource := testAccMongoDBAtlasClusterConfigGlobal(clusterResourceName, projectID, clusterName, "false") + clusterData := testAccMongoDBAtlasPrivateEndpointRegionalModeClusterData(clusterResourceName, resourceName, endpointResourceName) + + return fmt.Sprintf(` + resource "mongodbatlas_private_endpoint_regional_mode" %[1]q { + project_id = %[2]q + enabled = %[3]t + } + + %[4]s + + %[5]s + + %[6]s + `, resourceName, projectID, enabled, clusterResource, clusterData, endpointResources) +} + +func testAccCheckMongoDBAtlasPrivateEndpointRegionalModeExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + fmt.Printf("==========================================================================\n") + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + rs, ok := s.RootModule().Resources[resourceName] + + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + projectID := rs.Primary.ID + + _, _, err := conn.PrivateEndpoints.GetRegionalizedPrivateEndpointSetting(context.Background(), projectID) + + if err == nil { + return nil + } + + return fmt.Errorf("regional mode for project_id (%s) does not exist", projectID) + } +} + +func testAccCheckMongoDBAtlasPrivateEndpointRegionalModeClustersUpToDate(projectID, clusterName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + status, _, _ := conn.Clusters.Status(context.Background(), projectID, clusterName) + + if status.ChangeStatus == matlas.ChangeStatusPending { + return fmt.Errorf("cluster (%s) for project (%s) still has changes PENDING", clusterName, projectID) + } + + rs, ok := s.RootModule().Resources["mongodbatlas_cluster.global_cluster"] + + if !ok { + return fmt.Errorf("Could not find resource state for cluster (%s) on project (%s)", clusterName, projectID) + } + + var rsPrivateEndpointCount int + var err error + + if rsPrivateEndpointCount, err = strconv.Atoi(rs.Primary.Attributes["connection_strings.0.private_endpoint.#"]); err != nil { + return fmt.Errorf("Connection strings private endpoint count is not a number") + } + + cluster, _, _ := conn.Clusters.Get(context.Background(), projectID, clusterName) + + fmt.Printf("testAccCheckMongoDBAtlasPrivateEndpointRegionalModeClustersUpToDate %#v \n", rs.Primary.Attributes) + fmt.Printf("cluster.ConnectionStrings %#v \n", flattenConnectionStrings(cluster.ConnectionStrings)) + + if rsPrivateEndpointCount != len(cluster.ConnectionStrings.PrivateEndpoint) { + return fmt.Errorf("Cluster PrivateEndpoint count does not match resource") + } + + if rs.Primary.Attributes["connection_strings.0.standard"] != cluster.ConnectionStrings.Standard { + return fmt.Errorf("Cluster standard connection_string does not match resource") + } + + if rs.Primary.Attributes["connection_strings.0.standard_srv"] != cluster.ConnectionStrings.StandardSrv { + return fmt.Errorf("Cluster standard connection_string does not match resource") + } + + return nil + } +} + +func testAccCheckMongoDBAtlasPrivateEndpointRegionalModeDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*MongoDBClient).Atlas + + for _, rs := range s.RootModule().Resources { + if rs.Type != "mongodbatlas_private_endpoint_regional_mode" { + continue + } + + setting, _, err := conn.PrivateEndpoints.GetRegionalizedPrivateEndpointSetting(context.Background(), rs.Primary.ID) + + if err != nil { + return fmt.Errorf("Could not read regionalized private endpoint setting for project %q", rs.Primary.ID) + } + + if setting.Enabled != false { + return fmt.Errorf("Regionalized private endpoint setting for project %q was not properly disabled", rs.Primary.ID) + } + } + + return nil +} diff --git a/mongodbatlas/resource_mongodbatlas_privatelink_endpoint_service_test.go b/mongodbatlas/resource_mongodbatlas_privatelink_endpoint_service_test.go index d0114af841..d27931a088 100644 --- a/mongodbatlas/resource_mongodbatlas_privatelink_endpoint_service_test.go +++ b/mongodbatlas/resource_mongodbatlas_privatelink_endpoint_service_test.go @@ -13,7 +13,8 @@ import ( func TestAccResourceMongoDBAtlasPrivateLinkEndpointServiceAWS_Complete(t *testing.T) { SkipTestExtCred(t) var ( - resourceName = "mongodbatlas_privatelink_endpoint_service.test" + resourceSuffix = "test" + resourceName = fmt.Sprintf("mongodbatlas_privatelink_endpoint_service.%s", resourceSuffix) awsAccessKey = os.Getenv("AWS_ACCESS_KEY_ID") awsSecretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") @@ -33,7 +34,7 @@ func TestAccResourceMongoDBAtlasPrivateLinkEndpointServiceAWS_Complete(t *testin Steps: []resource.TestStep{ { Config: testAccMongoDBAtlasPrivateLinkEndpointServiceConfigCompleteAWS( - awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID, + awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID, resourceSuffix, ), Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasPrivateLinkEndpointServiceExists(resourceName), @@ -49,7 +50,8 @@ func TestAccResourceMongoDBAtlasPrivateLinkEndpointServiceAWS_Complete(t *testin func TestAccResourceMongoDBAtlasPrivateLinkEndpointServiceAWS_import(t *testing.T) { SkipTestExtCred(t) var ( - resourceName = "mongodbatlas_privatelink_endpoint_service.test" + resourceSuffix = "test" + resourceName = fmt.Sprintf("mongodbatlas_privatelink_endpoint_service.%s", resourceSuffix) awsAccessKey = os.Getenv("AWS_ACCESS_KEY_ID") awsSecretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") @@ -69,7 +71,7 @@ func TestAccResourceMongoDBAtlasPrivateLinkEndpointServiceAWS_import(t *testing. Steps: []resource.TestStep{ { Config: testAccMongoDBAtlasPrivateLinkEndpointServiceConfigCompleteAWS( - awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID, + awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID, resourceSuffix, ), Check: resource.ComposeTestCheckFunc( testAccCheckMongoDBAtlasPrivateLinkEndpointServiceExists(resourceName), @@ -144,7 +146,7 @@ func testAccCheckMongoDBAtlasPrivateLinkEndpointServiceDestroy(s *terraform.Stat return nil } -func testAccMongoDBAtlasPrivateLinkEndpointServiceConfigCompleteAWS(awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID string) string { +func testAccMongoDBAtlasPrivateLinkEndpointServiceConfigCompleteAWS(awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID, serviceResourceName string) string { return fmt.Sprintf(` provider "aws" { region = "%[5]s" @@ -167,11 +169,91 @@ func testAccMongoDBAtlasPrivateLinkEndpointServiceConfigCompleteAWS(awsAccessKey } - resource "mongodbatlas_privatelink_endpoint_service" "test" { + resource "mongodbatlas_privatelink_endpoint_service" %[9]q { project_id = mongodbatlas_privatelink_endpoint.test.project_id - endpoint_service_id = aws_vpc_endpoint.ptfe_service.id - private_link_id = mongodbatlas_privatelink_endpoint.test.id + endpoint_service_id = aws_vpc_endpoint.ptfe_service.id + private_link_id = mongodbatlas_privatelink_endpoint.test.id + provider_name = "%[4]s" + } + `, awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID, serviceResourceName) +} + +func testAccMongoDBAtlasPrivateLinkEndpointServiceConfigUnmanagedAWS(awsAccessKey, awsSecretKey, projectID, providerName, region, serviceResourceName string) string { + return fmt.Sprintf(` + provider "aws" { + region = "%[5]s" + access_key = "%[1]s" + secret_key = "%[2]s" + } + resource "mongodbatlas_privatelink_endpoint" "test" { + project_id = "%[3]s" provider_name = "%[4]s" + region = "%[5]s" + } + resource "aws_vpc_endpoint" "ptfe_service" { + vpc_id = aws_vpc.primary.id + service_name = mongodbatlas_privatelink_endpoint.test.endpoint_service_name + vpc_endpoint_type = "Interface" + subnet_ids = [aws_subnet.primary-az1.id] + security_group_ids = [aws_security_group.primary_default.id] + + } + resource "mongodbatlas_privatelink_endpoint_service" %[6]q { + project_id = mongodbatlas_privatelink_endpoint.test.project_id + endpoint_service_id = aws_vpc_endpoint.ptfe_service.id + private_link_id = mongodbatlas_privatelink_endpoint.test.id + provider_name = %[4]q + } + resource "aws_vpc" "primary" { + cidr_block = "10.0.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true + } + + resource "aws_internet_gateway" "primary" { + vpc_id = aws_vpc.primary.id + } + + resource "aws_route" "primary-internet_access" { + route_table_id = aws_vpc.primary.main_route_table_id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.primary.id } - `, awsAccessKey, awsSecretKey, projectID, providerName, region, vpcID, subnetID, securityGroupID) + + # Subnet-A + resource "aws_subnet" "primary-az1" { + vpc_id = aws_vpc.primary.id + cidr_block = "10.0.1.0/24" + map_public_ip_on_launch = true + availability_zone = "%[5]sa" + } + + # Subnet-B + resource "aws_subnet" "primary-az2" { + vpc_id = aws_vpc.primary.id + cidr_block = "10.0.2.0/24" + map_public_ip_on_launch = false + availability_zone = "%[5]sb" + } + + resource "aws_security_group" "primary_default" { + name_prefix = "default-" + description = "Default security group for all instances in vpc" + vpc_id = aws_vpc.primary.id + ingress { + from_port = 0 + to_port = 0 + protocol = "tcp" + cidr_blocks = [ + "0.0.0.0/0", + ] + } + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + `, awsAccessKey, awsSecretKey, projectID, providerName, region, serviceResourceName) } diff --git a/mongodbatlas/resource_mongodbatlas_project.go b/mongodbatlas/resource_mongodbatlas_project.go index b4160722eb..6ffb0ea0d4 100644 --- a/mongodbatlas/resource_mongodbatlas_project.go +++ b/mongodbatlas/resource_mongodbatlas_project.go @@ -97,6 +97,31 @@ func resourceMongoDBAtlasProject() *schema.Resource { }, }, }, + "is_collect_database_specifics_statistics_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "is_data_explorer_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "is_performance_advisor_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "is_realtime_performance_panel_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "is_schema_advisor_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, }, } } @@ -151,6 +176,23 @@ func resourceMongoDBAtlasProjectCreate(ctx context.Context, d *schema.ResourceDa } } + projectSettings := &matlas.ProjectSettings{} + + projectSettings.IsCollectDatabaseSpecificsStatisticsEnabled = pointy.Bool(d.Get("is_collect_database_specifics_statistics_enabled").(bool)) + + projectSettings.IsDataExplorerEnabled = pointy.Bool(d.Get("is_data_explorer_enabled").(bool)) + + projectSettings.IsPerformanceAdvisorEnabled = pointy.Bool(d.Get("is_performance_advisor_enabled").(bool)) + + projectSettings.IsRealtimePerformancePanelEnabled = pointy.Bool(d.Get("is_realtime_performance_panel_enabled").(bool)) + + projectSettings.IsSchemaAdvisorEnabled = pointy.Bool(d.Get("is_schema_advisor_enabled").(bool)) + + _, _, err = conn.Projects.UpdateProjectSettings(ctx, project.ID, projectSettings) + if err != nil { + return diag.Errorf("error updating project's settings assigned (%s): %s", project.ID, err) + } + d.SetId(project.ID) return resourceMongoDBAtlasProjectRead(ctx, d, meta) @@ -184,6 +226,11 @@ func resourceMongoDBAtlasProjectRead(ctx context.Context, d *schema.ResourceData log.Println("[WARN] `api_keys` will be empty because the user has no permissions to read the api keys endpoint") } + projectSettings, _, err := conn.Projects.GetProjectSettings(ctx, projectID) + if err != nil { + return diag.Errorf("error getting project's settings assigned (%s): %s", projectID, err) + } + if err := d.Set("name", projectRes.Name); err != nil { return diag.Errorf(errorProjectSetting, `name`, projectID, err) } @@ -208,6 +255,22 @@ func resourceMongoDBAtlasProjectRead(ctx context.Context, d *schema.ResourceData return diag.Errorf(errorProjectSetting, `api_keys`, projectID, err) } + if err := d.Set("is_collect_database_specifics_statistics_enabled", projectSettings.IsCollectDatabaseSpecificsStatisticsEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_collect_database_specifics_statistics_enabled`, projectID, err) + } + if err := d.Set("is_data_explorer_enabled", projectSettings.IsDataExplorerEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_data_explorer_enabled`, projectID, err) + } + if err := d.Set("is_performance_advisor_enabled", projectSettings.IsPerformanceAdvisorEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_performance_advisor_enabled`, projectID, err) + } + if err := d.Set("is_realtime_performance_panel_enabled", projectSettings.IsRealtimePerformancePanelEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_realtime_performance_panel_enabled`, projectID, err) + } + if err := d.Set("is_schema_advisor_enabled", projectSettings.IsSchemaAdvisorEnabled); err != nil { + return diag.Errorf(errorProjectSetting, `is_schema_advisor_enabled`, projectID, err) + } + return nil } @@ -292,6 +355,35 @@ func resourceMongoDBAtlasProjectUpdate(ctx context.Context, d *schema.ResourceDa } } + projectSettings, _, err := conn.Projects.GetProjectSettings(ctx, projectID) + + if err != nil { + return diag.Errorf("error getting project's settings assigned (%s): %s", projectID, err) + } + + if d.HasChange("is_collect_database_specifics_statistics_enabled") { + projectSettings.IsCollectDatabaseSpecificsStatisticsEnabled = pointy.Bool(d.Get("is_collect_database_specifics_statistics_enabled").(bool)) + } + + if d.HasChange("is_data_explorer_enabled") { + projectSettings.IsDataExplorerEnabled = pointy.Bool(d.Get("is_data_explorer_enabled").(bool)) + } + if d.HasChange("is_performance_advisor_enabled") { + projectSettings.IsPerformanceAdvisorEnabled = pointy.Bool(d.Get("is_performance_advisor_enabled").(bool)) + } + if d.HasChange("is_realtime_performance_panel_enabled") { + projectSettings.IsRealtimePerformancePanelEnabled = pointy.Bool(d.Get("is_realtime_performance_panel_enabled").(bool)) + } + if d.HasChange("is_schema_advisor_enabled") { + projectSettings.IsSchemaAdvisorEnabled = pointy.Bool(d.Get("is_schema_advisor_enabled").(bool)) + } + if d.HasChange("is_collect_database_specifics_statistics_enabled") || d.HasChange("is_data_explorer_enabled") || + d.HasChange("is_performance_advisor_enabled") || d.HasChange("is_realtime_performance_panel_enabled") || d.HasChange("is_schema_advisor_enabled") { + _, _, err := conn.Projects.UpdateProjectSettings(ctx, projectID, projectSettings) + if err != nil { + return diag.Errorf("error updating project's settings assigned (%s): %s", projectID, err) + } + } return resourceMongoDBAtlasProjectRead(ctx, d, meta) } diff --git a/mongodbatlas/resource_mongodbatlas_project_test.go b/mongodbatlas/resource_mongodbatlas_project_test.go index ff590fdd82..9b6b29b1d8 100644 --- a/mongodbatlas/resource_mongodbatlas_project_test.go +++ b/mongodbatlas/resource_mongodbatlas_project_test.go @@ -204,6 +204,33 @@ func TestAccResourceMongoDBAtlasProject_CreateWithFalseDefaultSettings(t *testin }) } +func TestAccResourceMongoDBAtlasProject_CreateWithFalseDefaultAdvSettings(t *testing.T) { + var ( + project matlas.Project + resourceName = "mongodbatlas_project.test" + projectName = fmt.Sprintf("testacc-project-%s", acctest.RandString(10)) + orgID = os.Getenv("MONGODB_ATLAS_ORG_ID") + projectOwnerID = os.Getenv("MONGODB_ATLAS_PROJECT_OWNER_ID") + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckMongoDBAtlasProjectDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMongoDBAtlasProjectConfigWithFalseDefaultAdvSettings(projectName, orgID, projectOwnerID), + Check: resource.ComposeTestCheckFunc( + testAccCheckMongoDBAtlasProjectExists(resourceName, &project), + testAccCheckMongoDBAtlasProjectAttributes(&project, projectName), + resource.TestCheckResourceAttr(resourceName, "name", projectName), + resource.TestCheckResourceAttr(resourceName, "org_id", orgID), + ), + }, + }, + }) +} + func TestAccResourceMongoDBAtlasProject_withUpdatedRole(t *testing.T) { var ( resourceName = "mongodbatlas_project.test" @@ -428,6 +455,22 @@ func testAccMongoDBAtlasProjectConfigWithFalseDefaultSettings(projectName, orgID `, projectName, orgID, projectOwnerID) } +func testAccMongoDBAtlasProjectConfigWithFalseDefaultAdvSettings(projectName, orgID, projectOwnerID string) string { + return fmt.Sprintf(` + resource "mongodbatlas_project" "test" { + name = "%[1]s" + org_id = "%[2]s" + project_owner_id = "%[3]s" + with_default_alerts_settings = false + is_collect_database_specifics_statistics_enabled = false + is_data_explorer_enabled = false + is_performance_advisor_enabled = false + is_realtime_performance_panel_enabled = false + is_schema_advisor_enabled = false + } + `, projectName, orgID, projectOwnerID) +} + func testAccMongoDBAtlasProjectConfigWithAdvancedCluster(projectName, orgID, projectOwnerID, clusterName string) string { return fmt.Sprintf(` resource "mongodbatlas_project" "test" { diff --git a/mongodbatlas/resource_mongodbatlas_third_party_integration.go b/mongodbatlas/resource_mongodbatlas_third_party_integration.go index bbb10a27c4..2ec5bf57eb 100644 --- a/mongodbatlas/resource_mongodbatlas_third_party_integration.go +++ b/mongodbatlas/resource_mongodbatlas_third_party_integration.go @@ -19,16 +19,20 @@ var integrationTypes = []string{ "VICTOR_OPS", "FLOWDOCK", "WEBHOOK", + "MICROSOFT_TEAMS", + "PROMETHEUS", } var requiredPerType = map[string][]string{ - "PAGER_DUTY": {"service_key"}, - "DATADOG": {"api_key", "region"}, - "NEW_RELIC": {"license_key", "account_id", "write_token", "read_token"}, - "OPS_GENIE": {"api_key", "region"}, - "VICTOR_OPS": {"api_key"}, - "FLOWDOCK": {"flow_name", "api_token", "org_name"}, - "WEBHOOK": {"url"}, + "PAGER_DUTY": {"service_key"}, + "DATADOG": {"api_key", "region"}, + "NEW_RELIC": {"license_key", "account_id", "write_token", "read_token"}, + "OPS_GENIE": {"api_key", "region"}, + "VICTOR_OPS": {"api_key"}, + "FLOWDOCK": {"flow_name", "api_token", "org_name"}, + "WEBHOOK": {"url"}, + "MICROSOFT_TEAMS": {"microsoft_teams_webhook_url"}, + "PROMETHEUS": {"user_name", "password", "service_discovery", "scheme", "enabled"}, } func resourceMongoDBAtlasThirdPartyIntegration() *schema.Resource { @@ -120,6 +124,34 @@ func resourceMongoDBAtlasThirdPartyIntegration() *schema.Resource { Optional: true, Sensitive: true, }, + "microsoft_teams_webhook_url": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + }, + "user_name": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + }, + "password": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + }, + "service_discovery": { + Type: schema.TypeString, + Sensitive: true, + Optional: true, + }, + "scheme": { + Type: schema.TypeString, + Optional: true, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, }, } } diff --git a/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user.go b/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user.go index 4980757ac5..511e91b397 100644 --- a/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user.go +++ b/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user.go @@ -142,7 +142,7 @@ func resourceMongoDBAtlasX509AuthDBUserRead(ctx context.Context, d *schema.Resou ) if username != "" { - certificates, _, err = conn.X509AuthDBUsers.GetUserCertificates(ctx, projectID, username) + certificates, _, err = conn.X509AuthDBUsers.GetUserCertificates(ctx, projectID, username, nil) if err != nil { // new resource missing reset := strings.Contains(err.Error(), "404") && !d.IsNewResource() @@ -200,7 +200,7 @@ func resourceMongoDBAtlasX509AuthDBUserImportState(ctx context.Context, d *schem projectID := parts[0] if username != "" { - _, _, err := conn.X509AuthDBUsers.GetUserCertificates(ctx, projectID, username) + _, _, err := conn.X509AuthDBUsers.GetUserCertificates(ctx, projectID, username, nil) if err != nil { return nil, fmt.Errorf(errorX509AuthDBUsersRead, username, projectID, err) } diff --git a/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user_test.go b/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user_test.go index 54e471bdee..88c1b73720 100644 --- a/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user_test.go +++ b/mongodbatlas/resource_mongodbatlas_x509_authentication_database_user_test.go @@ -184,7 +184,7 @@ func testAccCheckMongoDBAtlasX509AuthDBUserExists(resourceName string) resource. ids := decodeStateID(rs.Primary.ID) if ids["current_certificate"] != "" { - if _, _, err := conn.X509AuthDBUsers.GetUserCertificates(context.Background(), ids["project_id"], ids["username"]); err == nil { + if _, _, err := conn.X509AuthDBUsers.GetUserCertificates(context.Background(), ids["project_id"], ids["username"], nil); err == nil { return nil } @@ -210,7 +210,7 @@ func testAccCheckMongoDBAtlasX509AuthDBUserDestroy(s *terraform.State) error { ids := decodeStateID(rs.Primary.ID) if ids["current_certificate"] != "" { - _, _, err := conn.X509AuthDBUsers.GetUserCertificates(context.Background(), ids["project_id"], ids["username"]) + _, _, err := conn.X509AuthDBUsers.GetUserCertificates(context.Background(), ids["project_id"], ids["username"], nil) if err == nil { /* There is no way to remove one user certificate so until this comes it will keep in this way diff --git a/website/docs/d/cloud_backup_schedule.html.markdown b/website/docs/d/cloud_backup_schedule.html.markdown index 3958f4637f..a5d491c85c 100644 --- a/website/docs/d/cloud_backup_schedule.html.markdown +++ b/website/docs/d/cloud_backup_schedule.html.markdown @@ -61,7 +61,14 @@ In addition to all arguments above, the following attributes are exported: * `policy_item_daily` - Daily policy item * `policy_item_weekly` - Weekly policy item * `policy_item_monthly` - Monthly policy item - +* `auto_export_enabled` - Flag that indicates whether automatic export of cloud backup snapshots to the AWS bucket is enabled. Value can be one of the following: + + true - enables automatic export of cloud backup snapshots to the AWS bucket + false - disables automatic export of cloud backup snapshots to the AWS bucket (default) +* `use_org_and_group_names_in_export_prefix` - Specify true to use organization and project names instead of organization and project UUIDs in the path for the metadata files that Atlas uploads to your S3 bucket after it finishes exporting the snapshots. To learn more about the metadata files that Atlas uploads, see [Export Cloud Backup Snapshot](https://www.mongodb.com/docs/atlas/backup/cloud-backup/export/#std-label-cloud-provider-snapshot-export). +### Export +* `export_bucket_id` - Unique identifier of the mongodbatlas_cloud_backup_snapshot_export_bucket export_bucket_id value. +* `frequency_type` - Frequency associated with the export snapshot item. ### Policy Item Hourly * * `id` - Unique identifier of the backup policy item. diff --git a/website/docs/d/event_trigger.html.markdown b/website/docs/d/event_trigger.html.markdown index 1867b46d73..38c5a66aa5 100644 --- a/website/docs/d/event_trigger.html.markdown +++ b/website/docs/d/event_trigger.html.markdown @@ -64,6 +64,7 @@ In addition to all arguments above, the following attributes are exported: * `config_match` - A [$match](https://docs.mongodb.com/manual/reference/operator/aggregation/match/) expression document that MongoDB Realm includes in the underlying change stream pipeline for the trigger. * `config_project` - A [$project](https://docs.mongodb.com/manual/reference/operator/aggregation/project/) expression document that Realm uses to filter the fields that appear in change event objects. * `config_full_document` - If true, indicates that `UPDATE` change events should include the most current [majority-committed](https://docs.mongodb.com/manual/reference/read-concern-majority/) version of the modified document in the fullDocument field. +* `unordered` - Only Available for Database Triggers. If true, event ordering is disabled and this trigger can process events in parallel. If false, event ordering is enabled and the trigger executes serially. * `config_schedule` - A [cron expression](https://docs.mongodb.com/realm/triggers/cron-expressions/) that defines the trigger schedule. * `event_processors` - An object where each field name is an event processor ID and each value is an object that configures its corresponding event processor. * `event_processors.0.aws_eventbridge.config_account_id` - AWS Account ID. diff --git a/website/docs/d/event_triggers.html.markdown b/website/docs/d/event_triggers.html.markdown index 4e3c9870ad..00006cb061 100644 --- a/website/docs/d/event_triggers.html.markdown +++ b/website/docs/d/event_triggers.html.markdown @@ -66,6 +66,7 @@ In addition to all arguments above, the following attributes are exported: * `config_match` - A [$match](https://docs.mongodb.com/manual/reference/operator/aggregation/match/) expression document that MongoDB Realm includes in the underlying change stream pipeline for the trigger. * `config_project` - A [$project](https://docs.mongodb.com/manual/reference/operator/aggregation/project/) expression document that Realm uses to filter the fields that appear in change event objects. * `config_full_document` - If true, indicates that `UPDATE` change events should include the most current [majority-committed](https://docs.mongodb.com/manual/reference/read-concern-majority/) version of the modified document in the fullDocument field. +* `unordered` - Sort order for `DATABASE` type. * `config_schedule` - A [cron expression](https://docs.mongodb.com/realm/triggers/cron-expressions/) that defines the trigger schedule. * `event_processors` - An object where each field name is an event processor ID and each value is an object that configures its corresponding event processor. * `event_processors.0.aws_eventbridge.config_account_id` - AWS Account ID. diff --git a/website/docs/d/federated_settings.html.markdown b/website/docs/d/federated_settings.html.markdown new file mode 100644 index 0000000000..11fa13e3b6 --- /dev/null +++ b/website/docs/d/federated_settings.html.markdown @@ -0,0 +1,39 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings" +sidebar_current: "docs-mongodbatlas-datasource-federated-settings" +description: |- + Provides a federated settings data source. +--- + +# mongodbatlas_federated_settings + +`mongodbatlas_federated_settings` provides a federated settings data source. Atlas Cloud federated settings provides federated settings outputs. + + +## Example Usage + +```terraform +data "mongodbatlas_federated_settings" "settings" { + org_id = "627a9683e7f7f7ff7fe306f14" +} +``` + +## Argument Reference +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + + +### FederatedSettings + +* `federated_domains` - List that contains the domains associated with the organization's identity provider. +* `has_role_mappings` - Flag that indicates whether this organization has role mappings configured. +* `id` - Unique 24-hexadecimal digit string that identifies this federation. +* `identity_provider_id` - Unique 20-hexadecimal digit string that identifies the identity provider connected to this organization. +* `identity_provider_status` - Value that indicates whether the identity provider is active. Atlas returns ACTIVE if the identity provider is active and INACTIVE if the identity provider is inactive. + + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) diff --git a/website/docs/d/federated_settings_identity_provider.html.markdown b/website/docs/d/federated_settings_identity_provider.html.markdown new file mode 100644 index 0000000000..94475190bd --- /dev/null +++ b/website/docs/d/federated_settings_identity_provider.html.markdown @@ -0,0 +1,87 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_identity_provider" +sidebar_current: "docs-mongodbatlas-datasource-federated-settings-identity-provider" +description: |- + Provides a federated settings Organization identity provider data source. +--- + +# mongodbatlas_federated_settings_identity_provider + +`mongodbatlas_federated_settings_identity_provider` provides a federated settings identity provider data source. Atlas federated settings identity provider provides federated settings outputs for the configured identity provider. + + +## Example Usage + +```terraform +resource "mongodbatlas_federated_settings_identity_provider" "identity_provider" { + federation_settings_id = "627a9687f7f7f7f774de306f14" + name = "mongodb_federation_test" + associated_domains = ["yourdomain.com"] + sso_debug_enabled = true + status = "ACTIVE" + sso_url = "https://mysso.oktapreview.com/app/mysso_terraformtest_1/exk177f7f7f70h8/sso/saml" + issuer_uri = "http://www.okta.com/exk17f7f7f7f7p50h8" + request_binding = "HTTP-POST" + response_signature_algorithm = "SHA-256" +} + +data "mongodbatlas_federated_settings_identity_provider" "identity_provider_ds" { + federation_settings_id = mongodbatlas_federated_settings_identity_provider.identity_provider.id + identity_provider_id = "0oad47f7fXnk1297" +} + +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `identity_provider_id` - (Required) Unique 20-hexadecimal digit string that identifies the IdP. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + + +### FederatedSettingsIdentityProvider + +* `acs_url` - Assertion consumer service URL to which the IdP sends the SAML response. +* `associated_domains` - List that contains the configured domains from which users can log in for this IdP. +* `associated_orgs` - List that contains the organizations from which users can log in for this IdP. +* `domain_allow_list` - List that contains the approved domains from which organization users can log in. +* `domain_restriction_enabled` - Flag that indicates whether domain restriction is enabled for the connected organization. +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. +* `post_auth_role_grants` - List that contains the default roles granted to users who authenticate through the IdP in a connected organization. If you provide a postAuthRoleGrants field in the request, the array that you provide replaces the current postAuthRoleGrants. + + ### Role_mappings +* `external_group_name` - Unique human-readable label that identifies the identity provider group to which this role mapping applies. +* `id` - Unique 24-hexadecimal digit string that identifies this role mapping. +* `role_assignments` - Atlas roles and the unique identifiers of the groups and organizations associated with each role. +* `group_id` - Unique identifier of the project to which you want the role mapping to apply. +* `role` - Specifies the Role that is attached to the Role Mapping. +### User Conflicts +* `email_address` - Email address of the the user that conflicts with selected domains. +* `federation_settings_id` - Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `first_name` - First name of the the user that conflicts with selected domains. +* `last_name` - Last name of the the user that conflicts with selected domains. +* `user_id` - Name of the Atlas user that conflicts with selected domains. +* `audience_uri` - Identifier for the intended audience of the SAML Assertion. +* `display_name` - Human-readable label that identifies the IdP. +* `issuer_uri` - Identifier for the issuer of the SAML Assertion. +* `okta_idp_id` - Unique 20-hexadecimal digit string that identifies the IdP. +### Pem File Info - List that contains the file information, including: start date, and expiration date for the identity provider's PEM-encoded public key certificate. +* `not_after` - Expiration Date. +* `not_before` - Start Date. +* `file_name` - Filename of certificate +* `request_binding` - SAML Authentication Request Protocol binding used to send the AuthNRequest. Atlas supports the following binding values: + - HTTP POST + - HTTP REDIRECT +* `response_signature_algorithm` - Algorithm used to encrypt the IdP signature. Atlas supports the following signature algorithm values: + - SHA-1 + - SHA-256 +* `sso_debug_enabled` - Flag that indicates whether the IdP has enabled Bypass SAML Mode. Enabling this mode generates a URL that allows you bypass SAML and login to your organizations at any point. You can authenticate with this special URL only when Bypass Mode is enabled. Set this parameter to true during testing. This keeps you from getting locked out of MongoDB. +* `sso_url` - URL of the receiver of the SAML AuthNRequest. +* `status` - Label that indicates whether the identity provider is active. The IdP is Inactive until you map at least one domain to the IdP. + + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) diff --git a/website/docs/d/federated_settings_identity_providers.html.markdown b/website/docs/d/federated_settings_identity_providers.html.markdown new file mode 100644 index 0000000000..5dcddad870 --- /dev/null +++ b/website/docs/d/federated_settings_identity_providers.html.markdown @@ -0,0 +1,88 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_identity_providers" +sidebar_current: "docs-mongodbatlas-datasource-federated-settings-identity-providers" +description: |- + Provides a federated settings Organization Identity Provider datasource. +--- + +# mongodbatlas_federated_settings_identity_providers + +`mongodbatlas_federated_settings_identity_provider` provides an Federated Settings Identity Providers datasource. Atlas Cloud Federated Settings Identity Providers provides federated settings outputs for the configured Identity Providers. + + +## Example Usage + +```terraform +resource "mongodbatlas_federated_settings_identity_provider" "identity_provider" { + federation_settings_id = "627a9687f7f7f7f774de306f14" + name = "mongodb_federation_test" + associated_domains = ["yourdomain.com"] + sso_debug_enabled = true + status = "ACTIVE" +} + +data "mongodbatlas_federated_settings_identity_providers" "identitty_provider" { + federation_settings_id = mongodbatlas_federated_settings_identity_provider.identity_provider.id + page_num = 1 + items_per_page = 5 +} + +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `page_num` - (Optional) The page to return. Defaults to `1`. +* `items_per_page` - (Optional) Number of items to return per page, up to a maximum of 500. Defaults to `100`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `results` - Includes cloudProviderSnapshot object for each item detailed in the results array section. +* `totalCount` - Count of the total number of items in the result set. It may be greater than the number of objects in the results array if the entire result set is paginated. + +### FederatedSettingsIdentityProvider + +* `identity_provider_id` - Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `acs_url` - Assertion consumer service URL to which the IdP sends the SAML response. +* `associated_domains` - List that contains the configured domains from which users can log in for this IdP. +* `associated_orgs` - List that contains the configured domains from which users can log in for this IdP. +* `domain_allow_list` - List that contains the approved domains from which organization users can log in. +* `domain_restriction_enabled` - Flag that indicates whether domain restriction is enabled for the connected organization. +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. +* `post_auth_role_grants` - List that contains the default roles granted to users who authenticate through the IdP in a connected organization. If you provide a postAuthRoleGrants field in the request, the array that you provide replaces the current postAuthRoleGrants. + + ### Role_mappings +* `external_group_name` - Unique human-readable label that identifies the identity provider group to which this role mapping applies. +* `id` - Unique 24-hexadecimal digit string that identifies this role mapping. +* `role_assignments` - Atlas roles and the unique identifiers of the groups and organizations associated with each role. +* `group_id` - Unique identifier of the project to which you want the role mapping to apply. +* `role` - Specifies the Role that is attached to the Role Mapping. +### User Conflicts +* `email_address` - Email address of the the user that conflicts with selected domains. +* `federation_settings_id` - Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `first_name` - First name of the the user that conflicts with selected domains. +* `last_name` - Last name of the the user that conflicts with selected domains. +* `user_id` - Name of the Atlas user that conflicts with selected domains. +* `audience_uri` - Identifier for the intended audience of the SAML Assertion. +* `display_name` - Human-readable label that identifies the IdP. +* `issuer_uri` - Identifier for the issuer of the SAML Assertion. +* `idp_id` - Unique 20-hexadecimal digit string that identifies the IdP. +### Pem File Info - List that contains the file information, including: start date, and expiration date for the identity provider's PEM-encoded public key certificate. +* `not_after` - Expiration Date. +* `not_before` - Start Date. +* `file_name` - Filename of certificate +* `request_binding` - SAML Authentication Request Protocol binding used to send the AuthNRequest. Atlas supports the following binding values: + - HTTP POST + - HTTP REDIRECT +* `response_signature_algorithm` - Algorithm used to encrypt the IdP signature. Atlas supports the following signature algorithm values: + - SHA-1 + - SHA-256 +* `sso_debug_enabled` - Flag that indicates whether the IdP has enabled Bypass SAML Mode. Enabling this mode generates a URL that allows you bypass SAML and login to your organizations at any point. You can authenticate with this special URL only when Bypass Mode is enabled. Set this parameter to true during testing. This keeps you from getting locked out of MongoDB. +* `sso_url` - URL of the receiver of the SAML AuthNRequest. +* `status` - Label that indicates whether the identity provider is active. The IdP is Inactive until you map at least one domain to the IdP. + + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) diff --git a/website/docs/d/federated_settings_org_config.html.markdown b/website/docs/d/federated_settings_org_config.html.markdown new file mode 100644 index 0000000000..0284b8114b --- /dev/null +++ b/website/docs/d/federated_settings_org_config.html.markdown @@ -0,0 +1,59 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_org_config" +sidebar_current: "docs-mongodbatlas-datasource-federated-settings-org-config" +description: |- + Provides a federated settings Organization Configuration. +--- + +# mongodbatlas_federated_settings_org_configs + +`mongodbatlas_federated_settings_org_config` provides an Federated Settings Identity Providers datasource. Atlas Cloud Federated Settings Organizational configuration provides federated settings outputs for the configured Organizational configuration. + + +## Example Usage + +```terraform +resource "mongodbatlas_federated_settings_org_config" "org_connections" { + federation_settings_id = "627a9687f7f7f7f774de306f14" + org_id = "627a9683ea7ff7f74de306f14" + domain_restriction_enabled = false + domain_allow_list = ["mydomain.com"] +} + +data "mongodbatlas_federated_settings_org_config" "org_configs_ds" { + federation_settings_id = data.mongodbatlas_federated_settings_org_config.org_connections.id + org_id = "627a9683ea7ff7f74de306f14" +} +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +### FederatedSettingsOrgConfig + +* `domain_allow_list` - List that contains the approved domains from which organization users can log in. Note: If the organization uses an identity provider, `domain_allow_list` includes: any SSO domains associated with organization's identity provider and any custom domains associated with the specific organization. +* `domain_restriction_enabled` - Flag that indicates whether domain restriction is enabled for the connected organization. User Conflicts returns null when `domain_restriction_enabled` is false. +* `identity_provider_id` - Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `post_auth_role_grants` - List that contains the default [roles](https://www.mongodb.com/docs/atlas/reference/user-roles/#std-label-organization-roles) granted to users who authenticate through the IdP in a connected organization. If you provide a postAuthRoleGrants field in the request, the array that you provide replaces the current postAuthRoleGrants. + +### Role_mappings +* `external_group_name` - Unique human-readable label that identifies the identity provider group to which this role mapping applies. +* `id` - Unique 24-hexadecimal digit string that identifies this role mapping. +* `role_assignments` - Atlas roles and the unique identifiers of the groups and organizations associated with each role. +* `group_id` - Unique identifier of the project to which you want the role mapping to apply. +* `role` - Specifies the Role that is attached to the Role Mapping. +### User Conflicts +* `email_address` - Email address of the the user that conflicts with selected domains. +* `federation_settings_id` - Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `first_name` - First name of the the user that conflicts with selected domains. +* `last_name` - Last name of the the user that conflicts with selected domains. +* `user_id` - Name of the Atlas user that conflicts with selected domains. + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) diff --git a/website/docs/d/federated_settings_org_configs.html.markdown b/website/docs/d/federated_settings_org_configs.html.markdown new file mode 100644 index 0000000000..0529004a61 --- /dev/null +++ b/website/docs/d/federated_settings_org_configs.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_org_configs" +sidebar_current: "docs-mongodbatlas-datasource-federated-settings-org-configs" +description: |- + Provides a federated settings Organization Configurations. +--- + +# mongodbatlas_federated_settings_org_configs + +`mongodbatlas_federated_settings_org_configs` provides an Federated Settings Identity Providers datasource. Atlas Cloud Federated Settings Identity Providers provides federated settings outputs for the configured Identity Providers. + + +## Example Usage + +```terraform +resource "mongodbatlas_federated_settings_org_config" "org_connections" { + federation_settings_id = "627a9687f7f7f7f774de306f14" + org_id = "627a9683ea7ff7f74de306f14" + domain_restriction_enabled = false + domain_allow_list = ["mydomain.com"] +} + +data "mongodbatlas_federated_settings_org_configs" "org_configs_ds" { + federation_settings_id = data.mongodbatlas_federated_settings_org_config.org_connections.id +} +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `page_num` - (Optional) The page to return. Defaults to `1`. +* `items_per_page` - (Optional) Number of items to return per page, up to a maximum of 500. Defaults to `100`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `results` - Includes cloudProviderSnapshot object for each item detailed in the results array section. +* `totalCount` - Count of the total number of items in the result set. It may be greater than the number of objects in the results array if the entire result set is paginated. + +### FederatedSettingsOrgConfigs + +* `domain_allow_list` - List that contains the approved domains from which organization users can log in. +* `domain_restriction_enabled` - Flag that indicates whether domain restriction is enabled for the connected organization. +* `identity_provider_id` - Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. +* `post_auth_role_grants` - List that contains the default roles granted to users who authenticate through the IdP in a connected organization. If you provide a postAuthRoleGrants field in the request, the array that you provide replaces the current postAuthRoleGrants. + + ### Role_mappings +* `external_group_name` - Unique human-readable label that identifies the identity provider group to which this role mapping applies. +* `id` - Unique 24-hexadecimal digit string that identifies this role mapping. +* `role_assignments` - Atlas roles and the unique identifiers of the groups and organizations associated with each role. +* `group_id` - Unique identifier of the project to which you want the role mapping to apply. +* `role` - Specifies the Role that is attached to the Role Mapping. +### User Conflicts +* `email_address` - Email address of the the user that conflicts with selected domains. +* `federation_settings_id` - Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `first_name` - First name of the the user that conflicts with selected domains. +* `last_name` - Last name of the the user that conflicts with selected domains. +* `user_id` - Name of the Atlas user that conflicts with selected domains. + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) diff --git a/website/docs/d/federated_settings_org_role_mapping.html.markdown b/website/docs/d/federated_settings_org_role_mapping.html.markdown new file mode 100644 index 0000000000..1351c5a62e --- /dev/null +++ b/website/docs/d/federated_settings_org_role_mapping.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_role_mapping" +sidebar_current: "docs-mongodbatlas-datasource-federated-settings-role-mapping" +description: |- + Provides a federated settings Role Mapping datasource. +--- + +# mongodbatlas_federated_settings_org_role_mapping + +`mongodbatlas_federated_settings_org_role_mapping` provides an Federated Settings Org Role Mapping datasource. Atlas Cloud Federated Settings Org Role Mapping provides federated settings outputs for the configured Org Role Mapping. + + +## Example Usage + +```terraform +resource "mongodbatlas_federated_settings_org_role_mapping" "org_group_role_mapping_import" { + federation_settings_id = data.mongodbatlas_federated_settings.federated_settings.id + org_id = "627a9683e7f7f7ff7fe306f14" + + external_group_name = "myGrouptest" + + role_assignments { + org_id = "627a9683e7f7f7ff7fe306f14" + roles = ["ORG_MEMBER","ORG_GROUP_CREATOR","ORG_BILLING_ADMIN"] + } + + role_assignments { + group_id = "628aa20db7f7f7f98b81b8" + roles = ["GROUP_OWNER","GROUP_DATA_ACCESS_ADMIN","GROUP_SEARCH_INDEX_EDITOR","GROUP_DATA_ACCESS_READ_ONLY"] + } + + role_assignments { + group_id = "62b477f7f7f7f5e741489c" + roles = ["GROUP_OWNER","GROUP_DATA_ACCESS_ADMIN","GROUP_SEARCH_INDEX_EDITOR","GROUP_DATA_ACCESS_READ_ONLY","GROUP_DATA_ACCESS_READ_WRITE"] + } +} + +data "mongodbatlas_federated_settings_org_role_mapping" "role_mapping" { + federation_settings_id = mongodbatlas_federated_settings_org_role_mapping.org_group_role_mapping_import.id + org_id = "627a9683e7f7f7ff7fe306f14" + role_mapping_id = "627a9673e7f7f7ff7fe306f14" +} +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: +### FederatedSettingsOrgRoleMappings + +* `external_group_name` - Unique human-readable label that identifies the identity provider group to which this role mapping applies. +* `id` - Unique 24-hexadecimal digit string that identifies this role mapping. +* `role_assignments` - Atlas roles and the unique identifiers of the groups and organizations associated with each role. +* `group_id` - Unique identifier of the project to which you want the role mapping to apply. +* `role` - Specifies the Role that is attached to the Role Mapping. + + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) diff --git a/website/docs/d/federated_settings_org_role_mappings.html.markdown b/website/docs/d/federated_settings_org_role_mappings.html.markdown new file mode 100644 index 0000000000..4f52685931 --- /dev/null +++ b/website/docs/d/federated_settings_org_role_mappings.html.markdown @@ -0,0 +1,57 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_role_mappings" +sidebar_current: "docs-mongodbatlas-datasource-federated-settings-role-mappings" +description: |- + Provides a federated settings Role Mapping datasource. +--- + +# mongodbatlas_federated_settings_org_role_mappings + +`mongodbatlas_federated_settings_org_role_mappings` provides an Federated Settings Org Role Mapping datasource. Atlas Cloud Federated Settings Org Role Mapping provides federated settings outputs for the configured Org Role Mapping. + + +## Example Usage + +```terraform +resource "mongodbatlas_federated_settings_org_role_mapping" "org_group_role_mapping_import" { + federation_settings_id = "" + org_id = "627a9683e7f7f7ff7fe306f14" + group_id = "628aa20d7f7f7f7f7098b81b8" + external_group_name = "myGrouptest" + organization_roles = ["ORG_OWNER", "ORG_MEMBER", "ORG_BILLING_ADMIN", "ORG_GROUP_CREATOR", "ORG_READ_ONLY"] + group_roles = ["GROUP_OWNER","GROUP_CLUSTER_MANAGER","GROUP_DATA_ACCESS_ADMIN","GROUP_DATA_ACCESS_READ_WRITE","GROUP_SEARCH_INDEX_EDITOR","GROUP_DATA_ACCESS_READ_ONLY","GROUP_READ_ONLY"] +} + +data "mongodbatlas_federated_settings_org_role_mappings" "role_mappings" { + federation_settings_id = mongodbatlas_federated_settings_org_role_mapping.org_group_role_mapping_import.id + org_id = "627a9683e7f7f7ff7fe306f14" + page_num = 1 + items_per_page = 5 +} +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. +* `page_num` - (Optional) The page to return. Defaults to `1`. +* `items_per_page` - (Optional) Number of items to return per page, up to a maximum of 500. Defaults to `100`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `results` - Includes cloudProviderSnapshot object for each item detailed in the results array section. +* `totalCount` - Count of the total number of items in the result set. It may be greater than the number of objects in the results array if the entire result set is paginated. + +### FederatedSettingsOrgRoleMappings + +* `external_group_name` - Unique human-readable label that identifies the identity provider group to which this role mapping applies. +* `id` - Unique 24-hexadecimal digit string that identifies this role mapping. +* `role_assignments` - Atlas roles and the unique identifiers of the groups and organizations associated with each role. +* `group_id` - Unique identifier of the project to which you want the role mapping to apply. +* `role` - Specifies the Role that is attached to the Role Mapping. + + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) diff --git a/website/docs/d/private_endpoint_regional_mode.html.markdown b/website/docs/d/private_endpoint_regional_mode.html.markdown new file mode 100644 index 0000000000..2c51bf42fa --- /dev/null +++ b/website/docs/d/private_endpoint_regional_mode.html.markdown @@ -0,0 +1,37 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: private_endpoint_regional_mode" +sidebar_current: "docs-mongodbatlas-datasource-private-endpoint-regional-mode" +description: |- + Describes a Private Endpoint Regional Mode +--- + +# private_endpoint_regional_mode + +`private_endpoint_regional_mode` describe a Private Endpoint Regional Mode. This represents a Private Endpoint Regional Mode Connection that wants to retrieve settings of an Atlas project. + +-> **NOTE:** Groups and projects are synonymous terms. You may find group_id in the official documentation. + +## Example Usage + +```terraform +resource "private_endpoint_regional_mode" "test" { + project_id = "" +} + +data "private_endpoint_regional_mode" "test" { + project_id = private_endpoint_regional_mode.test.project_id +} +``` + +## Argument Reference +* `project_id` - (Required) Unique identifier for the project. +* `enabled` - (Optional) Flag that indicates whether the regionalized private endpoitn setting is enabled for the project. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The Terraform's unique identifier used internally for state management. + +See detailed information for arguments and attributes: **Private Endpoints** [Get Regional Mode](https://www.mongodb.com/docs/atlas/reference/api/private-endpoints-get-regional-mode/) | [Update Regional Mode](https://www.mongodb.com/docs/atlas/reference/api/private-endpoints-update-regional-mode/) \ No newline at end of file diff --git a/website/docs/d/project.html.markdown b/website/docs/d/project.html.markdown index 12f836e34d..c2c771624a 100644 --- a/website/docs/d/project.html.markdown +++ b/website/docs/d/project.html.markdown @@ -96,4 +96,11 @@ The following are valid roles: * `GROUP_DATA_ACCESS_READ_ONLY` * `GROUP_CLUSTER_MANAGER` + +* `is_collect_database_specifics_statistics_enabled` - Flag that indicates whether to enable statistics in [cluster metrics](https://www.mongodb.com/docs/atlas/monitor-cluster-metrics/) collection for the project. +* `is_data_explorer_enabled` - Flag that indicates whether to enable Data Explorer for the project. If enabled, you can query your database with an easy to use interface. +* `is_performance_advisor_enabled` - Flag that indicates whether to enable Performance Advisor and Profiler for the project. If enabled, you can analyze database logs to recommend performance improvements. +* `is_realtime_performance_panel_enabled` - Flag that indicates whether to enable Real Time Performance Panel for the project. If enabled, you can see real time metrics from your MongoDB database. +* `is_schema_advisor_enabled` - Flag that indicates whether to enable Schema Advisor for the project. If enabled, you receive customized recommendations to optimize your data model and enhance performance. Disable this setting to disable schema suggestions in the [Performance Advisor](https://www.mongodb.com/docs/atlas/performance-advisor/#std-label-performance-advisor) and the [Data Explorer](https://www.mongodb.com/docs/atlas/atlas-ui/#std-label-atlas-ui). + See [MongoDB Atlas API - Project](https://docs.atlas.mongodb.com/reference/api/project-get-one/) - [and MongoDB Atlas API - Teams](https://docs.atlas.mongodb.com/reference/api/project-get-teams/) Documentation for more information. diff --git a/website/docs/d/projects.html.markdown b/website/docs/d/projects.html.markdown index 602e8d5ee0..00e7ad4003 100644 --- a/website/docs/d/projects.html.markdown +++ b/website/docs/d/projects.html.markdown @@ -76,5 +76,10 @@ The following are valid roles: * `GROUP_DATA_ACCESS_READ_ONLY` * `GROUP_CLUSTER_MANAGER` - +* `is_collect_database_specifics_statistics_enabled` - Flag that indicates whether to enable statistics in [cluster metrics](https://www.mongodb.com/docs/atlas/monitor-cluster-metrics/) collection for the project. +* `is_data_explorer_enabled` - Flag that indicates whether to enable Data Explorer for the project. If enabled, you can query your database with an easy to use interface. +* `is_performance_advisor_enabled` - Flag that indicates whether to enable Performance Advisor and Profiler for the project. If enabled, you can analyze database logs to recommend performance improvements. +* `is_realtime_performance_panel_enabled` - Flag that indicates whether to enable Real Time Performance Panel for the project. If enabled, you can see real time metrics from your MongoDB database. +* `is_schema_advisor_enabled` - Flag that indicates whether to enable Schema Advisor for the project. If enabled, you receive customized recommendations to optimize your data model and enhance performance. Disable this setting to disable schema suggestions in the [Performance Advisor](https://www.mongodb.com/docs/atlas/performance-advisor/#std-label-performance-advisor) and the [Data Explorer](https://www.mongodb.com/docs/atlas/atlas-ui/#std-label-atlas-ui). + See [MongoDB Atlas API - Projects](https://docs.atlas.mongodb.com/reference/api/project-get-all/) - [and MongoDB Atlas API - Teams](https://docs.atlas.mongodb.com/reference/api/project-get-teams/) Documentation for more information. diff --git a/website/docs/d/third_party_integration.markdown b/website/docs/d/third_party_integration.markdown index 2e15e9f2a4..5b996f6e63 100644 --- a/website/docs/d/third_party_integration.markdown +++ b/website/docs/d/third_party_integration.markdown @@ -40,6 +40,8 @@ data "mongodbatlas_third_party_integration" "test" { * VICTOR_OPS * FLOWDOCK * WEBHOOK + * MICROSOFT_TEAMS + * PROMETHEUS ## Attributes Reference @@ -74,5 +76,13 @@ Additional values based on Type * `WEBHOOK` * `url` - Your webhook URL. * `secret` - An optional field for your webhook secret. +* `MICROSOFT_TEAMS` + * `microsoft_teams_webhook_url` - Your Microsoft Teams incoming webhook URL. + * `PROMETHEUS` + * `user_name` - Your Prometheus username. + * `password` - Your Prometheus password. + * `service_discovery` - Indicates which service discovery method is used, either file or http. + * `scheme` - Your Prometheus protocol scheme configured for requests. + * `enabled` - Whether your cluster has Prometheus enabled. See [MongoDB Atlas API](https://docs.atlas.mongodb.com/reference/api/third-party-integration-settings-get-one/) Documentation for more information. \ No newline at end of file diff --git a/website/docs/d/third_party_integrations.markdown b/website/docs/d/third_party_integrations.markdown index e2f019c7c8..bfa79b993a 100644 --- a/website/docs/d/third_party_integrations.markdown +++ b/website/docs/d/third_party_integrations.markdown @@ -77,5 +77,13 @@ Additional values based on Type * `WEBHOOK` * `url` - Your webhook URL. * `secret` - An optional field for your webhook secret. +* `MICROSOFT_TEAMS` + * `name` - Your Microsoft Teams incoming webhook name. + * `microsoft_teams_webhook_url` - Your Microsoft Teams incoming webhook URL. + * `PROMETHEUS` + * `user_name` - Your Prometheus username. + * `service_discovery` - Indicates which service discovery method is used, either file or http. + * `scheme` - Your Prometheus protocol scheme configured for requests. + * `enabled` - Whether your cluster has Prometheus enabled. See [MongoDB Atlas API](https://docs.atlas.mongodb.com/reference/api/third-party-integration-settings-get-all/) Documentation for more information. \ No newline at end of file diff --git a/website/docs/guides/1.4.0-upgrade-guide.html.markdown b/website/docs/guides/1.4.0-upgrade-guide.html.markdown new file mode 100644 index 0000000000..f39efd2a41 --- /dev/null +++ b/website/docs/guides/1.4.0-upgrade-guide.html.markdown @@ -0,0 +1,35 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas Provider 1.4.0: Upgrade and Information Guide" +sidebar_current: "docs-mongodbatlas-guides-140-upgrade-guide" +description: |- +MongoDB Atlas Provider 1.4.0: Upgrade and Information Guide +--- + +# MongoDB Atlas Provider 1.4.0: Upgrade and Information Guide + +The Terraform MongoDB Atlas Provider version 1.4.0 has a number of new and exciting features and changes. + +New Features: + +* You can now manage your federated authentication and authorization with [`mongodbatlas_federated_settings_identity_provider`](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/federated_settings_identity_provider), [`mongodbatlas_federated_settings_org_role_mapping`](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/federated_settings_org_role_mapping), and [`mongodbatlas_federated_settings_org_config`](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/federated_settings_org_config) +* You can now manage regionalized private endpoint status with [`mongodbatlas_private_endpoint_regional_mode`](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/private_endpoint_regional_mode) + +Changes: + +* You can now manage Prometheus with [mongodbatlas_third_party_integration](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/third_party_integration) +* You can now manage Microsoft Teams with [mongodbatlas_third_party_integration](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/third_party_integration) +* You can now use the argument `unordered` with [`mongodbatlas_event_trigger`](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/event_trigger) +* You can now manage project settings with [`mongodbatlas_project`](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/project) +* You can now enable cloud backup to automatiacially export backups to an AWS bucket with [`mongodbatlas_cloud_backup_schedule `](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/cloud_backup_schedule) + +1.4.0 also includes general improvements and bug fixes. See the [CHANGELOG](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/master/CHANGELOG.md) for more specific information. + +### Helpful Links + +* [Report bugs](https://github.com/mongodb/terraform-provider-mongodbatlas/issues) + +* [Request Features](https://feedback.mongodb.com/forums/924145-atlas?category_id=370723) + +* [Contact Support](https://docs.atlas.mongodb.com/support/) covered by MongoDB Atlas support plans, Developer and above. + \ No newline at end of file diff --git a/website/docs/r/cloud_backup_schedule.html.markdown b/website/docs/r/cloud_backup_schedule.html.markdown index 80ff0359c1..2b0f88e0ff 100644 --- a/website/docs/r/cloud_backup_schedule.html.markdown +++ b/website/docs/r/cloud_backup_schedule.html.markdown @@ -146,6 +146,14 @@ resource "mongodbatlas_cloud_backup_schedule" "test" { * `policy_item_daily` - (Optional) Daily policy item * `policy_item_weekly` - (Optional) Weekly policy item * `policy_item_monthly` - (Optional) Monthly policy item +* `auto_export_enabled` - Flag that indicates whether automatic export of cloud backup snapshots to the AWS bucket is enabled. Value can be one of the following: + + true - enables automatic export of cloud backup snapshots to the AWS bucket + false - disables automatic export of cloud backup snapshots to the AWS bucket (default) +* `use_org_and_group_names_in_export_prefix` - Specify true to use organization and project names instead of organization and project UUIDs in the path for the metadata files that Atlas uploads to your S3 bucket after it finishes exporting the snapshots. To learn more about the metadata files that Atlas uploads, see [Export Cloud Backup Snapshot](https://www.mongodb.com/docs/atlas/backup/cloud-backup/export/#std-label-cloud-provider-snapshot-export). +### Export +* `export_bucket_id` - Unique identifier of the mongodbatlas_cloud_backup_snapshot_export_bucket export_bucket_id value. +* `frequency_type` - Frequency associated with the export snapshot item. ### Policy Item Hourly * diff --git a/website/docs/r/event_trigger.html.markdown b/website/docs/r/event_trigger.html.markdown index 4921797315..e195cd8d48 100644 --- a/website/docs/r/event_trigger.html.markdown +++ b/website/docs/r/event_trigger.html.markdown @@ -52,6 +52,7 @@ resource "mongodbatlas_event_trigger" "test" { name = "NAME OF THE TRIGGER" type = "DATABASE" disabled = false + unordered = false config_operation_types = ["INSERT", "UPDATE"] config_operation_type = "LOGIN" config_providers = ["anon-user"] @@ -116,6 +117,7 @@ resource "mongodbatlas_event_trigger" "test" { * `config_match` - (Optional) Optional for `DATABASE` type. A [$match](https://docs.mongodb.com/manual/reference/operator/aggregation/match/) expression document that MongoDB Realm includes in the underlying change stream pipeline for the trigger. This is useful when you want to filter change events beyond their operation type. The trigger will only fire if the expression evaluates to true for a given change event. * `config_project` - (Optional) Optional for `DATABASE` type. A [$project](https://docs.mongodb.com/manual/reference/operator/aggregation/project/) expression document that Realm uses to filter the fields that appear in change event objects. * `config_full_document` - (Optional) Optional for `DATABASE` type. If true, indicates that `UPDATE` change events should include the most current [majority-committed](https://docs.mongodb.com/manual/reference/read-concern-majority/) version of the modified document in the fullDocument field. +* `unordered` - Only Available for Database Triggers. If true, event ordering is disabled and this trigger can process events in parallel. If false, event ordering is enabled and the trigger executes serially. * `config_schedule` - (Optional) Required for `SCHEDULED` type. A [cron expression](https://docs.mongodb.com/realm/triggers/cron-expressions/) that defines the trigger schedule. * `event_processors` - (Optional) An object where each field name is an event processor ID and each value is an object that configures its corresponding event processor. The following event processors are supported: `AWS_EVENTBRIDGE` For an example configuration object, see [Send Trigger Events to AWS EventBridge](https://docs.mongodb.com/realm/triggers/eventbridge/#std-label-event_processor_example). * `event_processors.0.aws_eventbridge.config_account_id` - (Optional) AWS Account ID. diff --git a/website/docs/r/federated_settings_identity_provider.html.markdown b/website/docs/r/federated_settings_identity_provider.html.markdown new file mode 100644 index 0000000000..cc6d44c85b --- /dev/null +++ b/website/docs/r/federated_settings_identity_provider.html.markdown @@ -0,0 +1,61 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_identity_provider" +sidebar_current: "docs-mongodbatlas-federated-settings-identity-provider" +description: |- + Provides a federated settings Identity Provider resource. +--- + +# mongodbatlas_federated_settings_identity_provider + +`mongodbatlas_federated_settings_identity_provider` provides an Atlas federated settings identity provider resource provides a subset of settings to be maintained post import of the existing resource. +## Example Usage + +~> **IMPORTANT** You **MUST** import this resource before you can manage it with this provider. + +```terraform +resource "mongodbatlas_federated_settings_identity_provider" "identity_provider" { + federation_settings_id = "627a9687f7f7f7f774de306f14" + name = "mongodb_federation_test" + associated_domains = ["yourdomain.com"] + sso_debug_enabled = true + status = "ACTIVE" + sso_url = "https://mysso.oktapreview.com/app/mysso_terraformtestsso/exk17q7f7f7f7f50h8/sso/saml" + issuer_uri = "http://www.okta.com/exk17q7f7f7f7fp50h8" + request_binding = "HTTP-POST" + response_signature_algorithm = "SHA-256" +} +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `name` - (Required) Human-readable label that identifies the identity provider. +* `associated_domains` - (Required) List that contains the domains associated with the identity provider. +* `sso_debug_enabled` - (Required) Flag that indicates whether the identity provider has SSO debug enabled. +* `status`- (Required) String enum that indicates whether the identity provider is active or not. Accepted values are ACTIVE or INACTIVE. +* `issuer_uri` - (Required) Unique string that identifies the issuer of the SAML +* `sso_url` - (Required) Unique string that identifies the intended audience of the SAML assertion. +* `request_binding` - (Required) SAML Authentication Request Protocol HTTP method binding (POST or REDIRECT) that Federated Authentication uses to send the authentication request. Atlas supports the following binding values: + - HTTP POST + - HTTP REDIRECT +* `response_signature_algorithm` - (Required) Signature algorithm that Federated Authentication uses to encrypt the identity provider signature. Valid values include SHA-1 and SHA-256. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + + +### FederatedSettingsIdentityProvider + +* `idp_id` - Unique 20-hexadecimal digit string that identifies the IdP. + +## Import + +Identity Provider **must** be imported before using federation_settings_id-idp_id, e.g. + +``` +$ terraform import mongodbatlas_federated_settings_identity_provider.identity_provider 6287a663c660f52b1c441c6c-0oad4fas87jL5Xnk1297 +``` + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) \ No newline at end of file diff --git a/website/docs/r/federated_settings_org_configs.html.markdown b/website/docs/r/federated_settings_org_configs.html.markdown new file mode 100644 index 0000000000..1115ba4edb --- /dev/null +++ b/website/docs/r/federated_settings_org_configs.html.markdown @@ -0,0 +1,53 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_org_config" +sidebar_current: "docs-mongodbatlas-resource-federated-settings-org-config" +description: |- + Provides a federated settings Organization Configuration. +--- + +# mongodbatlas_federated_settings_org_config + +`mongodbatlas_federated_settings_org_config` provides an Federated Settings Identity Providers datasource. Atlas Cloud Federated Settings Identity Providers provides federated settings outputs for the configured Identity Providers. + + +## Example Usage + +~> **IMPORTANT** You **MUST** import this resource before you can manage it with this provider. + +```terraform +resource "mongodbatlas_federated_settings_org_config" "org_connection" { + federation_settings_id = "627a9687f7f7f7f774de306f14" + org_id = "627a9683ea7ff7f74de306f14" + domain_restriction_enabled = false + domain_allow_list = ["mydomain.com"] + dentity_provider_id = "0oad4fas87jL7f75Xnk1297" +} + +data "mongodbatlas_federated_settings_org_configs" "org_configs_ds" { + federation_settings_id = data.mongodbatlas_federated_settings_org_config.org_connection.id +} +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `org_id` - (Required) Unique 24-hexadecimal digit string that identifies the organization that contains your projects. +* `domain_allow_list` - List that contains the approved domains from which organization users can log in. +* `domain_restriction_enabled` - (Required) Flag that indicates whether domain restriction is enabled for the connected organization. +* `identity_provider_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +## Import + +FederatedSettingsOrgConfig must be imported using federation_settings_id-org_id, e.g. + +``` +$ terraform import mongodbatlas_federated_settings_org_config.org_connection 6287a663c7f7f7f71c441c6c-627a96837f7f7f7e306f14-628ae97f7f7468ea3727 +``` + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) + diff --git a/website/docs/r/federated_settings_org_role_mapping.html.markdown b/website/docs/r/federated_settings_org_role_mapping.html.markdown new file mode 100644 index 0000000000..3ff68d3b85 --- /dev/null +++ b/website/docs/r/federated_settings_org_role_mapping.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: mongodbatlas_federated_settings_org_role_mapping" +sidebar_current: "docs-mongodbatlas-resource-federated-settings-org-role-mapping" +description: |- + Provides a federated settings Role Mapping resource. +--- + +# mongodbatlas_federated_settings_org_role_mapping + +`mongodbatlas_federated_settings_org_role_mapping` provides an Role Mapping resource. This allows organization role mapping to be created. + +## Example Usage + +```terraform +resource "mongodbatlas_federated_settings_org_role_mapping" "org_group_role_mapping_import" { + federation_settings_id = "627a9687f7f7f7f774de306f14" + org_id = "627a9683e7f7f7ff7fe306f14" + external_group_name = "myGrouptest" + + role_assignments { + org_id = "627a9683e7f7f7ff7fe306f14" + roles = ["ORG_MEMBER","ORG_GROUP_CREATOR","ORG_BILLING_ADMIN"] + } + + role_assignments { + group_id = "628aa20d7f7f7f7f7098b81b8" + roles = ["GROUP_OWNER","GROUP_DATA_ACCESS_ADMIN","GROUP_SEARCH_INDEX_EDITOR","GROUP_DATA_ACCESS_READ_ONLY"] + } + + role_assignments { + group_id = "628aa20d7f7f7f7f7078b81b8" + roles = ["GROUP_OWNER","GROUP_DATA_ACCESS_ADMIN","GROUP_SEARCH_INDEX_EDITOR","GROUP_DATA_ACCESS_READ_ONLY","GROUP_DATA_ACCESS_READ_WRITE"] + } +} +``` + +## Argument Reference + +* `federation_settings_id` - (Required) Unique 24-hexadecimal digit string that identifies the federated authentication configuration. +* `org_id` - Unique 24-hexadecimal digit string that identifies the organization that contains your projects. +* `external_group_name` - Unique human-readable label that identifies the identity provider group to which this role mapping applies. +* `role_assignments` - Atlas roles and the unique identifiers of the groups and organizations associated with each role. +* `group_id` - Unique identifier of the project to which you want the role mapping to apply. +* `roles` - Specifies the Roles that are attached to the Role Mapping. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: +* `id` - Unique 24-hexadecimal digit string that identifies this role mapping. + +## Import + +FederatedSettingsOrgRoleMapping can be imported using federation_settings_id-org_id-role_mapping_id, e.g. + +``` +$ terraform import mongodbatlas_federated_settings_org_role_mapping.org_group_role_mapping_import 6287a663c7f7f7f71c441c6c-627a96837f7f7f7e306f14-628ae97f7f7468ea3727 +``` + +For more information see: [MongoDB Atlas API Reference.](https://www.mongodb.com/docs/atlas/reference/api/federation-configuration/) \ No newline at end of file diff --git a/website/docs/r/private_endpoint_regional_mode.html.markdown b/website/docs/r/private_endpoint_regional_mode.html.markdown new file mode 100644 index 0000000000..8e848499ec --- /dev/null +++ b/website/docs/r/private_endpoint_regional_mode.html.markdown @@ -0,0 +1,142 @@ +--- +layout: "mongodbatlas" +page_title: "MongoDB Atlas: private_endpoint_regional_mode" +sidebar_current: "docs-mongodbatlas-resource-private_endpoint_regional_mode" +description: |- + Provides a Private Endpoint Regional Mode resource +--- + +# private_endpoint_regional_mode + +`mongodbatlas_private_endpoint_regional_mode` provides a Private Endpoint Regional Mode resource. This represents a regionalized private endpoint setting for a Project. Enable it to allow region specific private endpoints. + +~> **IMPORTANT:**You must have one of the following roles to successfully handle the resource: + * Organization Owner + * Project Owner + +-> **NOTE:** Groups and projects are synonymous terms. You may find group_id in the official documentation. + +~> **WARNING:**Your [connection strings](https://www.mongodb.com/docs/atlas/reference/faq/connection-changes/#std-label-connstring-privatelink) to existing multi-region and global sharded clusters change when you enable this setting. You must update your applications to use the new connection strings. This might cause downtime. + +## Example AWS Global Cluster with multiple Private Endpoint + +```terraform +resource "mongodbatlas_private_endpoint_regional_mode" "test" { + project_id = var.atlasprojectid + enabled = true +} + +resource "mongodbatlas_cluster" "cluster-atlas" { + project_id = var.atlasprojectid + name = "cluster-atlas" + cloud_backup = true + auto_scaling_disk_gb_enabled = true + mongo_db_major_version = "5.0" + cluster_type = "GEOSHARDED" + replication_specs { + zone_name = "Zone 1" + num_shards = 2 + regions_config { + region_name = "US_EAST_1" + electable_nodes = 3 + priority = 7 + read_only_nodes = 0 + } + } + + replication_specs { + zone_name = "Zone 2" + num_shards = 2 + regions_config { + region_name = "US_WEST_1" + electable_nodes = 3 + priority = 7 + read_only_nodes = 0 + } + } + # Provider settings + provider_name = "AWS" + disk_size_gb = 80 + provider_instance_size_name = "M30" +} + +data "mongodbatlas_cluster" "cluster-atlas" { + project_id = var.atlasprojectid + name = mongodbatlas_cluster.cluster-atlas.name + depends_on = [ + mongodbatlas_privatelink_endpoint_service.test_west, + mongodbatlas_privatelink_endpoint_service.test_east, + mongodbatlas_private_endpoint_regional_mode.test + ] +} + +resource "mongodbatlas_privatelink_endpoint" "test_west" { + project_id = var.atlasprojectid + provider_name = "AWS" + region = "US_WEST_1" +} + +resource "mongodbatlas_privatelink_endpoint_service" "test_west" { + project_id = mongodbatlas_privatelink_endpoint.test_west.project_id + private_link_id = mongodbatlas_privatelink_endpoint.test_west.private_link_id + endpoint_service_id = aws_vpc_endpoint.test_west.id + provider_name = "AWS" +} + +resource "aws_vpc_endpoint" "test_west" { + provider = aws.west + vpc_id = "vpc-7fc0a543" + service_name = mongodbatlas_privatelink_endpoint.test_west.endpoint_service_name + vpc_endpoint_type = "Interface" + subnet_ids = ["subnet-de0406d2"] + security_group_ids = ["sg-3f238186"] +} + +resource "mongodbatlas_privatelink_endpoint" "test_east" { + project_id = "var.atlasprojectid + provider_name = "AWS" + region = "US_WEST_1" +} + +resource "mongodbatlas_privatelink_endpoint_service" "test_east" { + project_id = mongodbatlas_privatelink_endpoint.test_east.project_id + private_link_id = mongodbatlas_privatelink_endpoint.test_east.private_link_id + endpoint_service_id = aws_vpc_endpoint.test_east.id + provider_name = "AWS" +} + +resource "aws_vpc_endpoint" "test_east" { + provider = aws.east + vpc_id = "vpc-345a0cf7" + service_name = mongodbatlas_privatelink_endpoint.test_east.endpoint_service_name + vpc_endpoint_type = "Interface" + subnet_ids = ["subnet-2d6040ed"] + security_group_ids = ["sg-681832f3"] +} + +``` + +## Argument Reference +* `project_id` - (Required) Unique identifier for the project. +* `enabled` - (Optional) Flag that indicates whether the regionalized private endpoint setting is enabled for the project. Set this value to true to create more than one private endpoint in a cloud provider region to connect to multi-region and global Atlas sharded clusters. You can enable this setting only if your Atlas project contains no replica sets. You can't disable this setting if you have: + * More than one private endpoint in more than one region, or + * More than one private endpoint in one region and one private endpoint in one or more regions. +You can create only sharded clusters when you enable the regionalized private endpoint setting. You can't create replica sets. + + +## Additional Reference + +In addition to the example shown above, keep in mind: +* `mongodbatlas_cluster.cluster-atlas.depends_on` - Make your cluster dependent on the project's `mongodbatlas_private_endpoint_regional_mode` as well as any relevant `mongodbatlas_privatelink_endpoint_service` resources. See an [example](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/master/examples/aws-atlas-privatelink-regionalized). +* `mongodbatlas_cluster.cluster-atlas.connection_strings` will differ based on the value of `mongodbatlas_private_endpoint_regional_mode.test.enabled`. +* For more information on usage with GCP, see [our Privatelink Endpoint Service documentation: Example with GCP](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/privatelink_endpoint_service#example-with-gcp) +* For more information on usage with Azure, see [our Privatelink Endpoint Service documentation: Examples with Azure](https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/privatelink_endpoint_service#example-with-azure) + +## Import +Private Endpoint Regional Mode can be imported using project id in format `{project_id}`, e.g. + +``` +$ terraform import mongodbatlas_private_endpoint_regional_mode.test 1112222b3bf99403840e8934 +``` + +See detailed information for arguments and attributes: **Private Endpoints** [Get Regional Mode](https://www.mongodb.com/docs/atlas/reference/api/private-endpoints-get-regional-mode/) | [Update Regional Mode](https://www.mongodb.com/docs/atlas/reference/api/private-endpoints-update-regional-mode/) \ No newline at end of file diff --git a/website/docs/r/project.html.markdown b/website/docs/r/project.html.markdown index 9506add96b..2597f52d45 100644 --- a/website/docs/r/project.html.markdown +++ b/website/docs/r/project.html.markdown @@ -34,6 +34,12 @@ resource "mongodbatlas_project" "test" { api_key_id = "61003b299dda8d54a9d7d10c" role_names = ["GROUP_READ_ONLY"] } + + is_collect_database_specifics_statistics_enabled = false + is_data_explorer_enabled = false + is_performance_advisor_enabled = true + is_realtime_performance_panel_enabled = false + is_schema_advisor_enabled = false } ``` @@ -74,8 +80,14 @@ api_keys allows one to assign an existing organization programmatic API key to a * `GROUP_DATA_ACCESS_ADMIN` * `GROUP_DATA_ACCESS_READ_WRITE` * `GROUP_DATA_ACCESS_READ_ONLY` - * `GROUP_CLUSTER_MANAGER` - + * `GROUP_CLUSTER_MANAGER` + +* `is_collect_database_specifics_statistics_enabled` - (Optional) Flag that indicates whether to enable statistics in [cluster metrics](https://www.mongodb.com/docs/atlas/monitor-cluster-metrics/) collection for the project. +* `is_data_explorer_enabled` - (Optional) Flag that indicates whether to enable Data Explorer for the project. If enabled, you can query your database with an easy to use interface. When Data Explorer is disabled, you cannot terminate slow operations from the [Real-Time Performance Panel](https://www.mongodb.com/docs/atlas/real-time-performance-panel/#std-label-real-time-metrics-status-tab) or create indexes from the [Performance Advisor](https://www.mongodb.com/docs/atlas/performance-advisor/#std-label-performance-advisor). You can still view Performance Advisor recommendations, but you must create those indexes from [mongosh](https://www.mongodb.com/docs/mongodb-shell/#mongodb-binary-bin.mongosh). +* `is_performance_advisor_enabled` - (Optional) Flag that indicates whether to enable Performance Advisor and Profiler for the project. If enabled, you can analyze database logs to recommend performance improvements. +* `is_realtime_performance_panel_enabled` - (Optional) Flag that indicates whether to enable Real Time Performance Panel for the project. If enabled, you can see real time metrics from your MongoDB database. +* `is_schema_advisor_enabled` - (Optional) Flag that indicates whether to enable Schema Advisor for the project. If enabled, you receive customized recommendations to optimize your data model and enhance performance. Disable this setting to disable schema suggestions in the [Performance Advisor](https://www.mongodb.com/docs/atlas/performance-advisor/#std-label-performance-advisor) and the [Data Explorer](https://www.mongodb.com/docs/atlas/atlas-ui/#std-label-atlas-ui). + ## Attributes Reference In addition to all arguments above, the following attributes are exported: diff --git a/website/docs/r/third_party_integration.markdown b/website/docs/r/third_party_integration.markdown index 91bffaea08..cd6911a28b 100644 --- a/website/docs/r/third_party_integration.markdown +++ b/website/docs/r/third_party_integration.markdown @@ -70,6 +70,14 @@ Additional values based on Type * `WEBHOOK` * `url` - Your webhook URL. * `secret` - An optional field for your webhook secret. +* `MICROSOFT_TEAMS` + * `microsoft_teams_webhook_url` - Your Microsoft Teams incoming webhook URL. + * `PROMETHEUS` + * `user_name` - Your Prometheus username. + * `password` - Your Prometheus password. + * `service_discovery` - Indicates which service discovery method is used, either file or http. + * `scheme` - Your Prometheus protocol scheme configured for requests. + * `enabled` - Whether your cluster has Prometheus enabled. ## Attributes Reference diff --git a/website/mongodbatlas.erb b/website/mongodbatlas.erb index 721d09d98c..c7be96acb4 100644 --- a/website/mongodbatlas.erb +++ b/website/mongodbatlas.erb @@ -17,6 +17,36 @@ > MongoDB Atlas Provider 0.6.0: Upgrade Guide + > + MongoDB Atlas Provider 0.8.0: Upgrade Guide + + > + MongoDB Atlas Provider 0.8.2: Upgrade Guide + + > + MongoDB Atlas Provider 0.9.0: Upgrade Guide + + > + MongoDB Atlas Provider 0.9.1: Upgrade Guide + + > + MongoDB Atlas Provider 1.0.0: Upgrade Guide + + > + MongoDB Atlas Provider 1.0.1: Upgrade Guide + + > + MongoDB Atlas Provider 1.1.0: Upgrade Guide + + > + MongoDB Atlas Provider 1.2.0: Upgrade Guide + + > + MongoDB Atlas Provider 1.3.0: Upgrade Guide + + > + MongoDB Atlas Provider 1.4.0: Upgrade Guide + @@ -105,6 +135,27 @@ > mongodbatlas_serverless_instances + > + mongodbatlas_federated_settings + + > + mongodbatlas_federated_settings_identity_provider + + > + mongodbatlas_federated_settings_identity_providers + + > + mongodbatlas_federated_settings_org_config + + > + mongodbatlas_federated_settings_org_configs + + > + mongodbatlas_federated_settings_org_role_mapping + + > + mongodbatlas_federated_settings_org_role_mappings + @@ -173,6 +224,15 @@ > mongodbatlas_serverless_instance + > + mongodbatlas_federated_settings_identity_provider + + > + mongodbatlas_federated_settings_org_config + + > + mongodbatlas_federated_settings_org_role_mapping +