Skip to content

Commit 1216148

Browse files
authored
Add cloudstack_domain as a data source (#195)
1 parent aba1fde commit 1216148

File tree

4 files changed

+306
-0
lines changed

4 files changed

+306
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
//
18+
19+
package cloudstack
20+
21+
import (
22+
"fmt"
23+
"log"
24+
25+
"github.com/apache/cloudstack-go/v2/cloudstack"
26+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
27+
)
28+
29+
func dataSourceCloudstackDomain() *schema.Resource {
30+
return &schema.Resource{
31+
Read: dataSourceCloudstackDomainRead,
32+
Schema: map[string]*schema.Schema{
33+
"filter": dataSourceFiltersSchema(),
34+
35+
// Computed values
36+
"domain_id": {
37+
Type: schema.TypeString,
38+
Computed: true,
39+
},
40+
"name": {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
},
44+
"network_domain": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
},
48+
"parent_domain_id": {
49+
Type: schema.TypeString,
50+
Computed: true,
51+
},
52+
},
53+
}
54+
}
55+
56+
func dataSourceCloudstackDomainRead(d *schema.ResourceData, meta interface{}) error {
57+
log.Printf("Domain Data Source Read Started")
58+
59+
cs := meta.(*cloudstack.CloudStackClient)
60+
p := cs.Domain.NewListDomainsParams()
61+
62+
var filterName, filterValue string
63+
var filterByName, filterByID bool
64+
65+
// Apply filters if provided
66+
if filters, filtersOk := d.GetOk("filter"); filtersOk {
67+
for _, f := range filters.(*schema.Set).List() {
68+
m := f.(map[string]interface{})
69+
name := m["name"].(string)
70+
value := m["value"].(string)
71+
72+
switch name {
73+
case "name":
74+
p.SetName(value)
75+
filterName = value
76+
filterByName = true
77+
log.Printf("[DEBUG] Filtering by name: %s", value)
78+
case "id":
79+
p.SetId(value)
80+
filterValue = value
81+
filterByID = true
82+
log.Printf("[DEBUG] Filtering by ID: %s", value)
83+
}
84+
}
85+
}
86+
87+
csDomains, err := cs.Domain.ListDomains(p)
88+
if err != nil {
89+
return fmt.Errorf("failed to list domains: %s", err)
90+
}
91+
92+
log.Printf("[DEBUG] Found %d domains from CloudStack API", len(csDomains.Domains))
93+
94+
var domain *cloudstack.Domain
95+
96+
// If we have results from the API call, select the appropriate domain
97+
if len(csDomains.Domains) > 0 {
98+
// If we filtered by ID or name through the API, we should have a specific result
99+
if filterByID || filterByName {
100+
// Since we used API filtering, the first result should be our match
101+
domain = csDomains.Domains[0]
102+
log.Printf("[DEBUG] Using API-filtered domain: %s", domain.Name)
103+
} else {
104+
// If no filters were applied, we need to handle this case
105+
// This shouldn't happen with the current schema as filters are required
106+
return fmt.Errorf("no filter criteria specified")
107+
}
108+
}
109+
110+
if domain == nil {
111+
if filterByName {
112+
return fmt.Errorf("no domain found with name: %s", filterName)
113+
} else if filterByID {
114+
return fmt.Errorf("no domain found with ID: %s", filterValue)
115+
} else {
116+
return fmt.Errorf("no domain found matching the specified criteria")
117+
}
118+
}
119+
120+
log.Printf("[DEBUG] Selected domain: %s (ID: %s)", domain.Name, domain.Id)
121+
122+
return domainDescriptionAttributes(d, domain)
123+
}
124+
125+
func domainDescriptionAttributes(d *schema.ResourceData, domain *cloudstack.Domain) error {
126+
d.SetId(domain.Id)
127+
d.Set("domain_id", domain.Id)
128+
d.Set("name", domain.Name)
129+
d.Set("network_domain", domain.Networkdomain)
130+
d.Set("parent_domain_id", domain.Parentdomainid)
131+
132+
return nil
133+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
//
18+
19+
package cloudstack
20+
21+
import (
22+
"fmt"
23+
"regexp"
24+
"testing"
25+
26+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id"
27+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
28+
"github.com/hashicorp/terraform-plugin-testing/terraform"
29+
)
30+
31+
func TestAccCloudstackDomainDataSource_basic(t *testing.T) {
32+
resourceName := "data.cloudstack_domain.my_domain"
33+
34+
resource.Test(t, resource.TestCase{
35+
PreCheck: func() { testAccPreCheck(t) },
36+
Providers: testAccProviders,
37+
Steps: []resource.TestStep{
38+
{
39+
Config: testAccCloudstackDomainDataSource_basic(),
40+
Check: resource.ComposeTestCheckFunc(
41+
testAccCheckCloudstackDomainDataSourceExists(resourceName),
42+
resource.TestCheckResourceAttr(resourceName, "name", "ROOT"),
43+
),
44+
},
45+
},
46+
})
47+
}
48+
49+
func testAccCheckCloudstackDomainDataSourceExists(n string) resource.TestCheckFunc {
50+
return func(s *terraform.State) error {
51+
rs, ok := s.RootModule().Resources[n]
52+
if !ok {
53+
return fmt.Errorf("Not found: %s", n)
54+
}
55+
56+
if rs.Primary.ID == "" {
57+
return fmt.Errorf("No Domain ID is set")
58+
}
59+
60+
return nil
61+
}
62+
}
63+
64+
func TestAccCloudstackDomainDataSource_invalidName(t *testing.T) {
65+
resource.Test(t, resource.TestCase{
66+
PreCheck: func() { testAccPreCheck(t) },
67+
Providers: testAccProviders,
68+
Steps: []resource.TestStep{
69+
{
70+
Config: testAccCloudstackDomainDataSource_invalidName(),
71+
ExpectError: regexp.MustCompile("no domain found with name: badgerbearocto"),
72+
},
73+
},
74+
})
75+
}
76+
77+
func testAccCloudstackDomainDataSource_basic() string {
78+
return `
79+
data "cloudstack_domain" "my_domain" {
80+
filter {
81+
name = "name"
82+
value = "ROOT"
83+
}
84+
}
85+
`
86+
}
87+
88+
func testAccCloudstackDomainDataSource_invalidName() string {
89+
return `
90+
data "cloudstack_domain" "my_domain" {
91+
filter {
92+
name = "name"
93+
value = "badgerbearocto"
94+
}
95+
}
96+
`
97+
}
98+
99+
func TestAccCloudstackDomainDataSource_byID(t *testing.T) {
100+
domainResourceName := "cloudstack_domain.test_domain"
101+
dataSourceName := "data.cloudstack_domain.my_domain_by_id"
102+
testDomainName := "test-domain-" + id.UniqueId()
103+
104+
resource.Test(t, resource.TestCase{
105+
PreCheck: func() { testAccPreCheck(t) },
106+
Providers: testAccProviders,
107+
Steps: []resource.TestStep{
108+
{
109+
Config: testAccCloudstackDomainDataSource_byID(testDomainName),
110+
Check: resource.ComposeTestCheckFunc(
111+
testAccCheckCloudstackDomainDataSourceExists(dataSourceName),
112+
resource.TestCheckResourceAttrPair(dataSourceName, "name", domainResourceName, "name"),
113+
resource.TestCheckResourceAttrPair(dataSourceName, "domain_id", domainResourceName, "id"),
114+
),
115+
},
116+
},
117+
})
118+
}
119+
120+
func testAccCloudstackDomainDataSource_byID(domainName string) string {
121+
return fmt.Sprintf(`
122+
resource "cloudstack_domain" "test_domain" {
123+
name = "%s"
124+
}
125+
126+
data "cloudstack_domain" "my_domain_by_id" {
127+
filter {
128+
name = "id"
129+
value = cloudstack_domain.test_domain.id
130+
}
131+
}
132+
`, domainName)
133+
}

cloudstack/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func Provider() *schema.Provider {
9090
"cloudstack_user": dataSourceCloudstackUser(),
9191
"cloudstack_vpn_connection": dataSourceCloudstackVPNConnection(),
9292
"cloudstack_pod": dataSourceCloudstackPod(),
93+
"cloudstack_domain": dataSourceCloudstackDomain(),
9394
"cloudstack_physicalnetwork": dataSourceCloudStackPhysicalNetwork(),
9495
},
9596

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
layout: default
3+
page_title: "CloudStack: cloudstack_domain Data Source"
4+
sidebar_current: "docs-cloudstack-datasource-domain"
5+
description: |-
6+
Retrieves information about a Domain
7+
---
8+
9+
# CloudStack: cloudstack_domain Data Source
10+
11+
A `cloudstack_domain` data source retrieves information about a domain within CloudStack.
12+
13+
## Example Usage
14+
15+
```hcl
16+
data "cloudstack_domain" "my_domain" {
17+
filter {
18+
name = "name"
19+
value = "ROOT"
20+
}
21+
}
22+
```
23+
24+
## Argument Reference
25+
26+
The following arguments are supported:
27+
28+
* `filter` - (Required) A block to filter the domains. The filter block supports the following:
29+
* `name` - (Required) The name of the filter.
30+
* `value` - (Required) The value of the filter.
31+
32+
## Attributes Reference
33+
34+
The following attributes are exported:
35+
36+
* `id` - The ID of the domain.
37+
* `name` - The name of the domain.
38+
* `network_domain` - The network domain for the domain.
39+
* `parent_domain_id` - The ID of the parent domain.

0 commit comments

Comments
 (0)