Skip to content

Commit

Permalink
Support both uuid and container id, update acceptance tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vicentepinto98 committed Dec 12, 2023
1 parent 97c60ae commit de0635e
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 39 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ generate-docs:
@echo "Generating documentation with tfplugindocs"
@$(SCRIPTS_BASE)/tfplugindocs.sh

build:
@go build -o bin/terraform-provider-stackit

# TEST
test:
@echo "Running tests for the terraform provider"
Expand Down
30 changes: 22 additions & 8 deletions stackit/internal/services/resourcemanager/project/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ func (d *projectDataSource) Configure(ctx context.Context, req datasource.Config
// Schema defines the schema for the data source.
func (d *projectDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
descriptions := map[string]string{
"main": "Resource Manager project data source schema.",
"main": "Resource Manager project data source schema. To identify the project, you need to provider either project_id or container_id. If you provide both, project_id will be used.",
"id": "Terraform's internal data source. ID. It is structured as \"`container_id`\".",
"project_id": "Project ID. It is an UUID.",
"container_id": "Project container ID.",
"parent_container_id": "Parent resource container ID. Both container ID (user-friendly) and UUID are supported",
"project_id": "Project UUID identifier. This is the ID that can be used in most of the other resources to identify the project.",
"container_id": "Project container ID. Globally unique, user-friendly identifier.",
"parent_container_id": "Parent resource identifier. Both container ID (user-friendly) and UUID are supported",
"name": "Project name.",
"labels": `Labels are key-value string pairs which can be attached to a resource container. A label key must match the regex [A-ZÄÜÖa-zäüöß0-9_-]{1,64}. A label value must match the regex ^$|[A-ZÄÜÖa-zäüöß0-9_-]{1,64}`,
}
Expand All @@ -108,14 +108,13 @@ func (d *projectDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
"project_id": schema.StringAttribute{
Description: descriptions["project_id"],
Optional: true,
Computed: true,
Validators: []validator.String{
validate.UUID(),
},
},
"container_id": schema.StringAttribute{
Description: descriptions["container_id"],
Required: true,
Optional: true,
Validators: []validator.String{
validate.NoSeparator(),
},
Expand Down Expand Up @@ -164,10 +163,25 @@ func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest
if resp.Diagnostics.HasError() {
return
}

projectId := state.ProjectId.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)

containerId := state.ContainerId.ValueString()
ctx = tflog.SetField(ctx, "project_id", containerId)
ctx = tflog.SetField(ctx, "container_id", containerId)

if containerId == "" && projectId == "" {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", "Either container_id or project_id must be set")
return
}

// set project identifier. If projectId is provided, it takes precedence over containerId
var identifier = containerId
if projectId != "" {
identifier = projectId
}

projectResp, err := d.client.GetProject(ctx, containerId).Execute()
projectResp, err := d.client.GetProject(ctx, identifier).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Calling API: %v", err))
return
Expand Down
6 changes: 3 additions & 3 deletions stackit/internal/services/resourcemanager/project/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ func (r *projectResource) Schema(_ context.Context, _ resource.SchemaRequest, re
descriptions := map[string]string{
"main": "Resource Manager project resource schema. To use this resource, it is required that you set the service account email in the provider configuration.",
"id": "Terraform's internal resource ID. It is structured as \"`container_id`\".",
"project_id": "Project ID. It is an UUID.",
"project_id": "Project UUID identifier. This is the ID that can be used in most of the other resources to identify the project.",
"container_id": "Project container ID. Globally unique, user-friendly identifier.",
"parent_container_id": "Parent resource container ID. Both container ID (user-friendly) and UUID are supported",
"parent_container_id": "Parent resource identifier. Both container ID (user-friendly) and UUID are supported",
"name": "Project name.",
"labels": "Labels are key-value string pairs which can be attached to a resource container. A label key must match the regex [A-ZÄÜÖa-zäüöß0-9_-]{1,64}. A label value must match the regex ^$|[A-ZÄÜÖa-zäüöß0-9_-]{1,64}",
"owner_email": "Email address of the owner of the project. This value is only considered during creation. Changing it afterwards will have no effect.",
Expand Down Expand Up @@ -402,7 +402,7 @@ func mapFields(ctx context.Context, projectResp *resourcemanager.ProjectResponse
model.ProjectId = types.StringValue(projectId)
model.ContainerId = types.StringValue(containerId)
if projectResp.Parent != nil {
if _, err := uuid.Parse(model.ContainerParentId.ValueString()); err != nil {
if _, err := uuid.Parse(model.ContainerParentId.ValueString()); err == nil {
// the provided containerParentId is the UUID identifier
model.ContainerParentId = types.StringPointerValue(projectResp.Parent.Id)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
var projectResource = map[string]string{
"name": fmt.Sprintf("acc-pj-%s", acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)),
"parent_container_id": testutil.TestProjectParentContainerID,
"parent_uuid": testutil.TestProjectParentUUID,
"billing_reference": "TEST-REF",
"new_label": "a-label",
}
Expand All @@ -29,16 +30,22 @@ func resourceConfig(name string, label *string) string {
labelConfig = fmt.Sprintf("new_label = %q", *label)
}
return fmt.Sprintf(`
%s
%[1]s
resource "stackit_resourcemanager_project" "project" {
parent_container_id = "%s"
name = "%s"
resource "stackit_resourcemanager_project" "project_container_id" {
parent_container_id = "%[2]s"
name = "%[3]s"
labels = {
"billing_reference" = "%s"
%s
"billing_reference" = "%[4]s"
%[5]s
}
owner_email = "%s"
owner_email = "%[6]s"
}
resource "stackit_resourcemanager_project" "project_uuid" {
parent_container_id = "%[7]s"
name = "%[3]s-uuid"
owner_email = "%[6]s"
}
`,
testutil.ResourceManagerProviderConfig(),
Expand All @@ -47,6 +54,7 @@ func resourceConfig(name string, label *string) string {
projectResource["billing_reference"],
labelConfig,
testutil.TestProjectServiceAccountEmail,
projectResource["parent_uuid"],
)
}

Expand All @@ -59,35 +67,68 @@ func TestAccResourceManagerResource(t *testing.T) {
{
Config: resourceConfig(projectResource["name"], nil),
Check: resource.ComposeAggregateTestCheckFunc(
// Project data
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project", "container_id"),
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project", "project_id"),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project", "name", projectResource["name"]),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project", "parent_container_id", projectResource["parent_container_id"]),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project", "labels.%", "1"),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project", "labels.billing_reference", projectResource["billing_reference"]),
// Parent container id project data
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project_container_id", "container_id"),
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project_container_id", "project_id"),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project_container_id", "name", projectResource["name"]),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project_container_id", "parent_container_id", projectResource["parent_container_id"]),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project_container_id", "labels.%", "1"),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project_container_id", "labels.billing_reference", projectResource["billing_reference"]),

// Parent UUID project data
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project_uuid", "container_id"),
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project_uuid", "project_id"),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project_uuid", "name", fmt.Sprintf("%s-uuid", projectResource["name"])),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project_uuid", "parent_container_id", projectResource["parent_uuid"]),
),
},
// Data source
{
Config: fmt.Sprintf(`
%s
data "stackit_resourcemanager_project" "project" {
container_id = stackit_resourcemanager_project.project.container_id
}`,
data "stackit_resourcemanager_project" "project_container" {
container_id = stackit_resourcemanager_project.project_container_id.container_id
}
data "stackit_resourcemanager_project" "project_uuid" {
project_id = stackit_resourcemanager_project.project_container_id.project_id
}
data "stackit_resourcemanager_project" "project_both" {
container_id = stackit_resourcemanager_project.project_container_id.container_id
project_id = stackit_resourcemanager_project.project_container_id.project_id
}
`,
resourceConfig(projectResource["name"], nil),
),
Check: resource.ComposeAggregateTestCheckFunc(
// Project data
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project", "id"),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project", "container_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project", "name", projectResource["name"]),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project", "parent_container_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project", "labels.%", "1"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project", "labels.billing_reference", projectResource["billing_reference"]),
resource.TestCheckResourceAttrPair("data.stackit_resourcemanager_project.project", "project_id",
"stackit_resourcemanager_project.project", "project_id"),
// Container project data
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_container", "id"),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_container", "container_id"),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_container", "project_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_container", "name", projectResource["name"]),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_container", "parent_container_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_container", "labels.%", "1"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_container", "labels.billing_reference", projectResource["billing_reference"]),

// UUID project data
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_uuid", "id"),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_uuid", "container_id"),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_uuid", "project_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_uuid", "name", projectResource["name"]),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_uuid", "parent_container_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_uuid", "labels.%", "1"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_uuid", "labels.billing_reference", projectResource["billing_reference"]),

// Both project data
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_both", "id"),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_both", "container_id"),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_both", "project_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_both", "name", projectResource["name"]),
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_project.project_both", "parent_container_id"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_both", "labels.%", "1"),
resource.TestCheckResourceAttr("data.stackit_resourcemanager_project.project_both", "labels.billing_reference", projectResource["billing_reference"]),
),
},
// Import
Expand Down Expand Up @@ -117,7 +158,6 @@ func TestAccResourceManagerResource(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
// Project data
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project", "container_id"),
resource.TestCheckResourceAttrSet("stackit_resourcemanager_project.project", "project_id"),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project", "name", fmt.Sprintf("%s-new", projectResource["name"])),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project", "parent_container_id", projectResource["parent_container_id"]),
resource.TestCheckResourceAttr("stackit_resourcemanager_project.project", "labels.%", "2"),
Expand Down
4 changes: 3 additions & 1 deletion stackit/internal/testutil/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ var (

// ProjectId is the id of project used for tests
ProjectId = os.Getenv("TF_ACC_PROJECT_ID")
// TestProjectParentContainerID is the container id of the organization under which projects are created as part of the resource-manager acceptance tests
// TestProjectParentContainerID is the container id of the parent resource under which projects are created as part of the resource-manager acceptance tests
TestProjectParentContainerID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID")
// TestProjectParentContainerID is the uuid of the parent resource under which projects are created as part of the resource-manager acceptance tests
TestProjectParentUUID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_UUID")
// TestProjectServiceAccountEmail is the e-mail of a service account with admin permissions on the organization under which projects are created as part of the resource-manager acceptance tests
TestProjectServiceAccountEmail = os.Getenv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL")

Expand Down

0 comments on commit de0635e

Please sign in to comment.