Skip to content

AAP-46310 Add aap_organization data source with name/id lookup support #107

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

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
652f22f
first draft replacement of pr#90
arrestle Jul 9, 2025
a24e452
fix ReturnAAPNamedURL to not use null ids that are not promised.
arrestle Jul 9, 2025
3029dbe
This is more accurate
arrestle Jul 9, 2025
c082607
update env hints
arrestle Jul 9, 2025
6cac4f1
change id to name
arrestle Jul 10, 2025
b4e5cd3
lint
arrestle Jul 10, 2025
fd3c1d6
simplify utils.go remove env.sh
arrestle Jul 10, 2025
05efbbd
simplify ReturnAAPNamedURL
arrestle Jul 11, 2025
3dfd9d5
keep pulling in files
arrestle Jul 11, 2025
27d94c0
Running Acceptance Tests
arrestle Jul 14, 2025
1c3057c
docs
arrestle Jul 14, 2025
47f28c4
missed checking for the randomInventoryName after creation
arrestle Jul 14, 2025
b6b0cda
add CheckDestroy
arrestle Jul 14, 2025
2dfa645
Merge remote-tracking branch 'upstream/main' into organization-data-s…
arrestle Jul 14, 2025
bb7fb3f
Release prep for v1.3.0-prerelease (#109)
davemulford Jul 10, 2025
640d7c0
Add text about linking workflow template to an organization and updat…
davemulford Jul 11, 2025
d362374
Merge branch 'organization-data-source' of github.com:arrestle/terraf…
arrestle Jul 14, 2025
a3a3a7c
merge fix for terraform plan with variables
arrestle Jul 14, 2025
42d4d6a
AAP_TEST_ORGANIZATION_ID needs to maatch Non-Default Org
arrestle Jul 14, 2025
f2af347
remove unnecc. computes
arrestle Jul 14, 2025
e135626
docs
arrestle Jul 14, 2025
19d5ef3
Update internal/provider/acceptance_test.go
arrestle Jul 15, 2025
429a7b8
rename file
arrestle Jul 15, 2025
8e9e40f
fix function name. clean up.
arrestle Jul 15, 2025
4134159
fix base_datasource to not allow name instead of id, doesn't apply to…
arrestle Jul 15, 2025
079eb85
override ConfigValidator for organization_data_source
arrestle Jul 15, 2025
be2e879
refactor and test CreateNamedURL
arrestle Jul 15, 2025
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 docs/data-sources/inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ output "inventory_details_with_name_and_org_name" {

- `id` (Number) Inventory id
- `name` (String) Name of the Inventory
- `organization` (Number) Identifier for the organization to which the Inventory belongs
- `organization_name` (String) The name for the organization to which the Inventory belongs

### Read-Only

- `description` (String) Description of the Inventory
- `named_url` (String) The Named Url of the Inventory
- `organization` (Number) Identifier for the organization to which the Inventory belongs
- `url` (String) Url of the Inventory
- `variables` (String, Deprecated) Variables of the Inventory. Will be either JSON or YAML string depending on how the variables were entered into AAP.
2 changes: 1 addition & 1 deletion docs/data-sources/job_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ output "job_template_with_name_and_org_name" {

- `id` (Number) JobTemplate id
- `name` (String) Name of the JobTemplate
- `organization` (Number) Identifier for the organization to which the JobTemplate belongs
- `organization_name` (String) The name for the organization to which the JobTemplate belongs

### Read-Only

- `description` (String) Description of the JobTemplate
- `named_url` (String) The Named Url of the JobTemplate
- `organization` (Number) Identifier for the organization to which the JobTemplate belongs
- `url` (String) Url of the JobTemplate
- `variables` (String, Deprecated) Variables of the JobTemplate. Will be either JSON or YAML string depending on how the variables were entered into AAP.
73 changes: 73 additions & 0 deletions docs/data-sources/organization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
page_title: "aap_organization Data Source - terraform-provider-aap"
description: |-
Get an existing Organization.
---

# aap_organization (Data Source)

Get an existing Organization.


## Example Usage

```terraform
terraform {
required_providers {
aap = {
source = "ansible/aap"
}
}
}

provider "aap" {
host = "https://AAP_HOST"
username = "ansible"
password = "test123!"
}

# You can look up Organizations by using either the `id` or their `name`.

# Look up organization by ID
data "aap_organization" "sample_by_id" {
id = 7
}

output "organization_with_id" {
value = data.aap_organization.sample_by_id
}

# Look up organization by name - this is the main use case for this data source
data "aap_organization" "sample_by_name" {
name = "Default"
}

output "organization_with_name" {
value = data.aap_organization.sample_by_name
}

# Example: Using the organization data source with an inventory resource
# This shows how to create an inventory in a specific organization by name
# instead of hard-coding the organization ID
resource "aap_inventory" "example" {
name = "My Inventory"
organization = data.aap_organization.sample_by_name.id
description = "An inventory created using the organization data source"
}
```


<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `id` (Number) Organization id
- `name` (String) Name of the Organization

### Read-Only

- `description` (String) Description of the Organization
- `named_url` (String) The Named Url of the Organization
- `url` (String) Url of the Organization
- `variables` (String, Deprecated) Variables of the Organization. Will be either JSON or YAML string depending on how the variables were entered into AAP.
2 changes: 1 addition & 1 deletion docs/data-sources/workflow_job_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ output "workflow_job_template_with_name_and_org_name" {

- `id` (Number) WorkflowJobTemplate id
- `name` (String) Name of the WorkflowJobTemplate
- `organization` (Number) Identifier for the organization to which the WorkflowJobTemplate belongs
- `organization_name` (String) The name for the organization to which the WorkflowJobTemplate belongs

### Read-Only

- `description` (String) Description of the WorkflowJobTemplate
- `named_url` (String) The Named Url of the WorkflowJobTemplate
- `organization` (Number) Identifier for the organization to which the WorkflowJobTemplate belongs
- `url` (String) Url of the WorkflowJobTemplate
- `variables` (String, Deprecated) Variables of the WorkflowJobTemplate. Will be either JSON or YAML string depending on how the variables were entered into AAP.
42 changes: 42 additions & 0 deletions examples/data-sources/aap_organization/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
terraform {
required_providers {
aap = {
source = "ansible/aap"
}
}
}

provider "aap" {
host = "https://AAP_HOST"
username = "ansible"
password = "test123!"
}

# You can look up Organizations by using either the `id` or their `name`.

# Look up organization by ID
data "aap_organization" "sample_by_id" {
id = 7
}

output "organization_with_id" {
value = data.aap_organization.sample_by_id
}

# Look up organization by name - this is the main use case for this data source
data "aap_organization" "sample_by_name" {
name = "Default"
}

output "organization_with_name" {
value = data.aap_organization.sample_by_name
}

# Example: Using the organization data source with an inventory resource
# This shows how to create an inventory in a specific organization by name
# instead of hard-coding the organization ID
resource "aap_inventory" "example" {
name = "My Inventory"
organization = data.aap_organization.sample_by_name.id
description = "An inventory created using the organization data source"
}
14 changes: 8 additions & 6 deletions internal/provider/base_datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ func (d *BaseDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, r
Description: fmt.Sprintf("The Named Url of the %s", d.DescriptiveEntityName),
},
"name": schema.StringAttribute{
Computed: true,
Optional: true,
Description: fmt.Sprintf("Name of the %s", d.DescriptiveEntityName),
},
Expand Down Expand Up @@ -115,11 +114,10 @@ func (d *BaseDataSourceWithOrg) Schema(_ context.Context, _ datasource.SchemaReq
Description: fmt.Sprintf("%s id", d.DescriptiveEntityName),
},
"organization": schema.Int64Attribute{
Computed: true,
Optional: true,
Description: fmt.Sprintf("Identifier for the organization to which the %s belongs", d.DescriptiveEntityName),
},
"organization_name": schema.StringAttribute{
Computed: true,
Optional: true,
Description: fmt.Sprintf("The name for the organization to which the %s belongs", d.DescriptiveEntityName),
},
Expand All @@ -132,7 +130,6 @@ func (d *BaseDataSourceWithOrg) Schema(_ context.Context, _ datasource.SchemaReq
Description: fmt.Sprintf("The Named Url of the %s", d.DescriptiveEntityName),
},
"name": schema.StringAttribute{
Computed: true,
Optional: true,
Description: fmt.Sprintf("Name of the %s", d.DescriptiveEntityName),
},
Expand Down Expand Up @@ -161,7 +158,8 @@ func (d *BaseDataSource) ConfigValidators(_ context.Context) []datasource.Config
return []datasource.ConfigValidator{
datasourcevalidator.Any(
datasourcevalidator.AtLeastOneOf(
tfpath.MatchRoot("id")),
tfpath.MatchRoot("id"),
tfpath.MatchRoot("name")),
),
}
}
Expand Down Expand Up @@ -207,11 +205,15 @@ func (d *BaseDataSource) ValidateConfig(ctx context.Context, req datasource.Vali
return
}

if IsValueProvidedOrPromised(data.Name) {
return
}

if !IsValueProvidedOrPromised(data.Id) {
resp.Diagnostics.AddAttributeWarning(
tfpath.Root("id"),
"Missing Attribute Configuration",
"Expected [id]",
"Expected [id] or [name]",
)
}
}
Expand Down
3 changes: 2 additions & 1 deletion internal/provider/base_datasource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ func TestDataSourceConfigValidators(t *testing.T) {
expected: []fwdatasource.ConfigValidator{
datasourcevalidator.Any(
datasourcevalidator.AtLeastOneOf(
tfpath.MatchRoot("id")),
tfpath.MatchRoot("id"),
tfpath.MatchRoot("name")),
),
},
},
Expand Down
1 change: 1 addition & 0 deletions internal/provider/general_api_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type BaseDetailSourceModel struct {
Variables customtypes.AAPCustomStringValue `tfsdk:"variables"`
}

// TF representation of the BaseDetailSourceModel with organization information.
type BaseDetailSourceModelWithOrg struct {
BaseDetailSourceModel
Organization tftypes.Int64 `tfsdk:"organization"`
Expand Down
54 changes: 54 additions & 0 deletions internal/provider/organization_acceptance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package provider

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

func TestAccInventoryResourceWithOrganizationDataSource(t *testing.T) {
randomInventoryName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
CheckDestroy: testAccCheckInventoryResourceDestroy,
Steps: []resource.TestStep{
// Create an inventory using the organization data source
{
Config: createOrganizationAndInventory("Default", randomInventoryName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.aap_organization.default_org", "id", "1"),
resource.TestCheckResourceAttr("data.aap_organization.default_org", "name", "Default"),
resource.TestCheckResourceAttr("data.aap_organization.default_org", "description", "The default organization for Ansible Automation Platform"),
resource.TestCheckResourceAttr("aap_inventory.new_inventory", "name", randomInventoryName),
resource.TestCheckResourceAttr("data.aap_inventory.the_created_inventory", "name", randomInventoryName),
resource.TestCheckResourceAttrPair("aap_inventory.new_inventory", "organization", "data.aap_inventory.the_created_inventory", "organization"),
resource.TestCheckResourceAttrPair("aap_inventory.new_inventory", "description", "data.aap_inventory.the_created_inventory", "description"),
resource.TestCheckResourceAttrPair("aap_inventory.new_inventory", "variables", "data.aap_inventory.the_created_inventory", "variables"),
resource.TestCheckResourceAttrPair("aap_inventory.new_inventory", "url", "data.aap_inventory.the_created_inventory", "url"),
),
},
},
})
}

func createOrganizationAndInventory(organizationName string, inventoryName string) string {
return fmt.Sprintf(`
data "aap_organization" "default_org" {
name = "%s"
}

resource "aap_inventory" "new_inventory" {
name = "%s"
organization = data.aap_organization.default_org.id
description = "A test inventory"
}

data "aap_inventory" "the_created_inventory" {
id = aap_inventory.new_inventory.id
}
`, organizationName, inventoryName)
}
31 changes: 31 additions & 0 deletions internal/provider/organization_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package provider

import (
"github.com/hashicorp/terraform-plugin-framework/datasource"
)

// Organization AAP API model
type OrganizationAPIModel struct {
BaseDetailAPIModel
}

// OrganizationDataSourceModel maps the data source schema data.
type OrganizationDataSourceModel struct {
BaseDetailSourceModel
}

// OrganizationDataSource is the data source implementation.
type OrganizationDataSource struct {
BaseDataSource
}

// NewOrganizationDataSource is a helper function to simplify the provider implementation.
func NewOrganizationDataSource() datasource.DataSource {
return &OrganizationDataSource{
BaseDataSource: *NewBaseDataSource(nil, StringDescriptions{
MetadataEntitySlug: "organization",
DescriptiveEntityName: "Organization",
ApiEntitySlug: "organizations",
}),
}
}
Loading