Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adds new ip_addresses computed attribute in mongodbatlas_project resource and data sources #1850

Merged
merged 17 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/code-health.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
with:
go-version-file: 'go.mod'
- name: Mock generation
run: make tools && mockery
run: make tools generate-mocks
- name: Check for uncommited files
run: |
export FILES=$(git ls-files -o -m --directory --exclude-standard --no-empty-directory)
Expand Down
16 changes: 11 additions & 5 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ filename: "{{ .InterfaceName | snakecase }}.go"
mockname: "{{.InterfaceName}}"

packages:
? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/searchdeployment
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mockery config file was not working as expected, only the last package (in this case advancedcluster) was used for generating mocks.

? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrest
? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/project
? github.com/mongodb/terraform-provider-mongodbatlas/internal/service/advancedcluster
: interfaces:
github.com/mongodb/terraform-provider-mongodbatlas/internal/service/searchdeployment:
interfaces:
DeploymentService:

github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrest:
interfaces:
EarService:

github.com/mongodb/terraform-provider-mongodbatlas/internal/service/project:
interfaces:
GroupProjectService:

github.com/mongodb/terraform-provider-mongodbatlas/internal/service/advancedcluster:
interfaces:
ClusterService:
4 changes: 4 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ link-git-hooks: ## Install git hooks
update-atlas-sdk: ## Update the atlas-sdk dependency
./scripts/update-sdk.sh

.PHONY: generate-mocks
generate-mocks: # uses mockery to generate mocks in folder `internal/testutil/mocksvc`
mockery

# e.g. run: make scaffold resource_name=streamInstance type=resource
# - type argument can have the values: `resource`, `data-source`, `plural-data-source`.
# details on usage can be found in CONTRIBUTING.md under "Scaffolding initial Code and File Structure"
Expand Down
57 changes: 45 additions & 12 deletions internal/service/project/data_source_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ type projectDS struct {
config.DSCommon
}

type TfProjectDSModel struct {
RegionUsageRestrictions types.String `tfsdk:"region_usage_restrictions"`
ProjectID types.String `tfsdk:"project_id"`
Name types.String `tfsdk:"name"`
OrgID types.String `tfsdk:"org_id"`
type TFProjectDSModel struct {
IPAddresses types.Object `tfsdk:"ip_addresses"`
Created types.String `tfsdk:"created"`
OrgID types.String `tfsdk:"org_id"`
RegionUsageRestrictions types.String `tfsdk:"region_usage_restrictions"`
ID types.String `tfsdk:"id"`
Limits []*TfLimitModel `tfsdk:"limits"`
Teams []*TfTeamDSModel `tfsdk:"teams"`
Name types.String `tfsdk:"name"`
ProjectID types.String `tfsdk:"project_id"`
Teams []*TFTeamDSModel `tfsdk:"teams"`
Limits []*TFLimitModel `tfsdk:"limits"`
ClusterCount types.Int64 `tfsdk:"cluster_count"`
IsCollectDatabaseSpecificsStatisticsEnabled types.Bool `tfsdk:"is_collect_database_specifics_statistics_enabled"`
IsRealtimePerformancePanelEnabled types.Bool `tfsdk:"is_realtime_performance_panel_enabled"`
Expand All @@ -48,7 +49,7 @@ type TfProjectDSModel struct {
IsDataExplorerEnabled types.Bool `tfsdk:"is_data_explorer_enabled"`
}

type TfTeamDSModel struct {
type TFTeamDSModel struct {
TeamID types.String `tfsdk:"team_id"`
RoleNames types.List `tfsdk:"role_names"`
}
Expand Down Expand Up @@ -137,12 +138,40 @@ func (d *projectDS) Schema(ctx context.Context, req datasource.SchemaRequest, re
},
},
},
"ip_addresses": schema.SingleNestedAttribute{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can something be used from project_ip_access_list resource/ds or they're different concepts?

Copy link
Member Author

@AgustinBettati AgustinBettati Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They seem to be different concepts. From testing I can see that it provides the IP address of each cluster node. This scope document gives some more details as to users that would leverage these ip addresses

Computed: true,
Attributes: map[string]schema.Attribute{
"services": schema.SingleNestedAttribute{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is services adding as opposed to not having it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I am sticking to the structure defined in the API. From the scope doc:

We will design the API schema in a way that's extensible (similar to the way SRE is designing theirs) so we can just add the bare minimum for now and future projects can add more.

I believe sticking to this structure will avoid breaking changes in the future as more services are added. Also synced with Zuhair on this in the jira comments.

Computed: true,
Attributes: map[string]schema.Attribute{
"clusters": schema.ListNestedAttribute{
Computed: true,
NestedObject: schema.NestedAttributeObject{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like IP addresses are associated to clusters in the project? wouldn't it make more sense then that IP addresses are returned in the clustest/adv_cluster resource instead of project? or in addition to be returned in project?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This a fair point. The main reason I see for including in the project resource is due to the endpoint being tagged in the project section (https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Projects/operation/returnAllIPAddresses).

Attributes: map[string]schema.Attribute{
"cluster_name": schema.StringAttribute{
Computed: true,
},
"inbound": schema.ListAttribute{
ElementType: types.StringType,
Computed: true,
},
"outbound": schema.ListAttribute{
ElementType: types.StringType,
Computed: true,
},
},
},
},
},
},
},
},
},
}
}

func (d *projectDS) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var projectState TfProjectDSModel
var projectState TFProjectDSModel
connV2 := d.Client.AtlasV2

resp.Diagnostics.Append(req.Config.Get(ctx, &projectState)...)
Expand Down Expand Up @@ -173,15 +202,19 @@ func (d *projectDS) Read(ctx context.Context, req datasource.ReadRequest, resp *
}
}

atlasTeams, atlasLimits, atlasProjectSettings, err := GetProjectPropsFromAPI(ctx, ServiceFromClient(connV2), project.GetId())
projectProps, err := GetProjectPropsFromAPI(ctx, ServiceFromClient(connV2), project.GetId())
if err != nil {
resp.Diagnostics.AddError("error when getting project properties", fmt.Sprintf(ErrorProjectRead, project.GetId(), err.Error()))
return
}

projectState = NewTFProjectDataSourceModel(ctx, project, atlasTeams, atlasProjectSettings, atlasLimits)
newProjectState, diags := NewTFProjectDataSourceModel(ctx, project, *projectProps)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &projectState)...)
resp.Diagnostics.Append(resp.State.Set(ctx, &newProjectState)...)
if resp.Diagnostics.HasError() {
return
}
Expand Down
39 changes: 21 additions & 18 deletions internal/service/project/data_source_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc"
)

const dataSourceName = "data.mongodbatlas_project.test"

func TestAccProjectDSProject_byID(t *testing.T) {
var (
projectName = acctest.RandomWithPrefix("test-acc")
Expand All @@ -36,9 +38,10 @@ func TestAccProjectDSProject_byID(t *testing.T) {
},
)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "name"),
resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "org_id"),
resource.TestCheckResourceAttr("mongodbatlas_project.test", "teams.#", "2"),
resource.TestCheckResourceAttrSet(dataSourceName, "name"),
resource.TestCheckResourceAttrSet(dataSourceName, "org_id"),
resource.TestCheckResourceAttr(dataSourceName, "teams.#", "2"),
resource.TestCheckResourceAttrSet(dataSourceName, "ip_addresses.services.clusters.#"),
lantoli marked this conversation as resolved.
Show resolved Hide resolved
),
},
},
Expand Down Expand Up @@ -69,9 +72,9 @@ func TestAccProjectDSProject_byName(t *testing.T) {
},
)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "name"),
resource.TestCheckResourceAttrSet("mongodbatlas_project.test", "org_id"),
resource.TestCheckResourceAttr("mongodbatlas_project.test", "teams.#", "2"),
resource.TestCheckResourceAttrSet(dataSourceName, "name"),
resource.TestCheckResourceAttrSet(dataSourceName, "org_id"),
resource.TestCheckResourceAttr(dataSourceName, "teams.#", "2"),
),
},
},
Expand Down Expand Up @@ -102,15 +105,15 @@ func TestAccProjectDSProject_defaultFlags(t *testing.T) {
},
)),
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_extended_storage_sizes_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"),
resource.TestCheckResourceAttr("mongodbatlas_project.test", "teams.#", "2"),
resource.TestCheckResourceAttrSet(dataSourceName, "name"),
resource.TestCheckResourceAttrSet(dataSourceName, "org_id"),
resource.TestCheckResourceAttrSet(dataSourceName, "is_collect_database_specifics_statistics_enabled"),
resource.TestCheckResourceAttrSet(dataSourceName, "is_data_explorer_enabled"),
resource.TestCheckResourceAttrSet(dataSourceName, "is_extended_storage_sizes_enabled"),
resource.TestCheckResourceAttrSet(dataSourceName, "is_performance_advisor_enabled"),
resource.TestCheckResourceAttrSet(dataSourceName, "is_realtime_performance_panel_enabled"),
resource.TestCheckResourceAttrSet(dataSourceName, "is_schema_advisor_enabled"),
resource.TestCheckResourceAttr(dataSourceName, "teams.#", "2"),
),
},
},
Expand All @@ -129,9 +132,9 @@ func TestAccProjectDSProject_limits(t *testing.T) {
{
Config: testAccMongoDBAtlasProjectDSByNameUsingRS(acc.ConfigProjectWithLimits(projectName, orgID, []*admin.DataFederationLimit{})),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.mongodbatlas_project.test", "name"),
resource.TestCheckResourceAttrSet("data.mongodbatlas_project.test", "org_id"),
resource.TestCheckResourceAttrSet("data.mongodbatlas_project.test", "limits.0.name"),
resource.TestCheckResourceAttrSet(dataSourceName, "name"),
resource.TestCheckResourceAttrSet(dataSourceName, "org_id"),
resource.TestCheckResourceAttrSet(dataSourceName, "limits.0.name"),
),
},
},
Expand Down
53 changes: 43 additions & 10 deletions internal/service/project/data_source_projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id"
"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
Expand All @@ -32,7 +33,7 @@ type ProjectsDS struct {

type tfProjectsDSModel struct {
ID types.String `tfsdk:"id"`
Results []*TfProjectDSModel `tfsdk:"results"`
Results []*TFProjectDSModel `tfsdk:"results"`
PageNum types.Int64 `tfsdk:"page_num"`
ItemsPerPage types.Int64 `tfsdk:"items_per_page"`
TotalCount types.Int64 `tfsdk:"total_count"`
Expand Down Expand Up @@ -134,6 +135,34 @@ func (d *ProjectsDS) Schema(ctx context.Context, req datasource.SchemaRequest, r
},
},
},
"ip_addresses": schema.SingleNestedAttribute{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can some part of the schema be reused from the RS or it's hard because here all are Computed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main limitation is that they are different schema types, terraform-plugin-framework/datasource/schema and terraform-plugin-framework/resource/schema respectively.

Computed: true,
Attributes: map[string]schema.Attribute{
"services": schema.SingleNestedAttribute{
Computed: true,
Attributes: map[string]schema.Attribute{
"clusters": schema.ListNestedAttribute{
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"cluster_name": schema.StringAttribute{
Computed: true,
},
"inbound": schema.ListAttribute{
ElementType: types.StringType,
Computed: true,
},
"outbound": schema.ListAttribute{
ElementType: types.StringType,
Computed: true,
},
},
},
},
},
},
},
},
},
},
},
Expand All @@ -157,9 +186,9 @@ func (d *ProjectsDS) Read(ctx context.Context, req datasource.ReadRequest, resp
return
}

err = populateProjectsDataSourceModel(ctx, connV2, &stateModel, projectsRes)
if err != nil {
resp.Diagnostics.AddError("error in monogbatlas_projects data source", err.Error())
diags := populateProjectsDataSourceModel(ctx, connV2, &stateModel, projectsRes)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

Expand All @@ -169,19 +198,23 @@ func (d *ProjectsDS) Read(ctx context.Context, req datasource.ReadRequest, resp
}
}

func populateProjectsDataSourceModel(ctx context.Context, connV2 *admin.APIClient, stateModel *tfProjectsDSModel, projectsRes *admin.PaginatedAtlasGroup) error {
func populateProjectsDataSourceModel(ctx context.Context, connV2 *admin.APIClient, stateModel *tfProjectsDSModel, projectsRes *admin.PaginatedAtlasGroup) diag.Diagnostics {
diagnostics := []diag.Diagnostic{}
input := projectsRes.GetResults()
results := make([]*TfProjectDSModel, 0, len(input))
results := make([]*TFProjectDSModel, 0, len(input))
for i := range input {
project := input[i]
atlasTeams, atlasLimits, atlasProjectSettings, err := GetProjectPropsFromAPI(ctx, ServiceFromClient(connV2), project.GetId())
projectProps, err := GetProjectPropsFromAPI(ctx, ServiceFromClient(connV2), project.GetId())
if err == nil { // if the project is still valid, e.g. could have just been deleted
projectModel := NewTFProjectDataSourceModel(ctx, &project, atlasTeams, atlasProjectSettings, atlasLimits)
results = append(results, &projectModel)
projectModel, diags := NewTFProjectDataSourceModel(ctx, &project, *projectProps)
diagnostics = append(diagnostics, diags...)
if projectModel != nil {
results = append(results, projectModel)
}
}
}
stateModel.Results = results
stateModel.TotalCount = types.Int64Value(int64(projectsRes.GetTotalCount()))
stateModel.ID = types.StringValue(id.UniqueId())
return nil
return diagnostics
}
Loading