Skip to content

Commit 021b0f8

Browse files
authored
New anti-affinity group resource and datasource (#415)
Depends on oxidecomputer/oxide.go#276 Closes: #416 Tested against the dogfood rack ```console $ TEST_ACC_NAME=TestAccCloudResourceAntiAffinityGroup_full make testacc -> Running terraform acceptance tests === RUN TestAccCloudResourceAntiAffinityGroup_full === PAUSE TestAccCloudResourceAntiAffinityGroup_full === CONT TestAccCloudResourceAntiAffinityGroup_full --- PASS: TestAccCloudResourceAntiAffinityGroup_full (4.44s) PASS ok github.com/oxidecomputer/terraform-provider-oxide/internal/provider 4.771s ``` ```console $ TEST_ACC_NAME=TestAccCloudDataSourceAntiAffinityGroup_full make testacc -> Running terraform acceptance tests === RUN TestAccCloudDataSourceAntiAffinityGroup_full === PAUSE TestAccCloudDataSourceAntiAffinityGroup_full === CONT TestAccCloudDataSourceAntiAffinityGroup_full --- PASS: TestAccCloudDataSourceAntiAffinityGroup_full (2.13s) PASS ok github.com/oxidecomputer/terraform-provider-oxide/internal/provider 2.454s ```
1 parent c55ad49 commit 021b0f8

10 files changed

+845
-3
lines changed

.changelog/0.8.0.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ description = ""
66
title = ""
77
description = ""
88

9+
[[features]]
10+
title = "New resource"
11+
description = "`oxide_anti_affinity_group` [#415](https://github.com/oxidecomputer/terraform-provider-oxide/pull/415)."
12+
13+
[[features]]
14+
title = "New data source"
15+
description = "`oxide_anti_affinity_group` [#415](https://github.com/oxidecomputer/terraform-provider-oxide/pull/415)."
16+
917
[[enhancements]]
1018
title = ""
1119
description = ""
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
page_title: "oxide_anti_affinity_group Data Source - terraform-provider-oxide"
3+
---
4+
5+
# oxide_anti_affinity_group (Data Source)
6+
7+
Retrieve information about a specified anti-affinity group.
8+
9+
## Example Usage
10+
11+
```hcl
12+
data "oxide_anti_affinity_group" "example" {
13+
project_name = "my-project"
14+
name = "my-group"
15+
timeouts = {
16+
read = "1m"
17+
}
18+
}
19+
```
20+
21+
## Schema
22+
23+
### Required
24+
25+
- `name` (String) Name of the anti-affinity group.
26+
- `project_name` (String) Name of the project that contains the anti-affinity group.
27+
28+
### Optional
29+
30+
- `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts))
31+
32+
### Read-Only
33+
34+
- `description` (String) Description of the anti-affinity group.
35+
- `failure_domain` (String) Describes the scope of affinity for the purposes of co-location.
36+
- `id` (String) Unique, immutable, system-controlled identifier for the anti-affinity group.
37+
- `policy` (String) Affinity policy used to describe what to do when a request cannot be satisfied.
38+
- `project_id` (String) ID of the project that contains the anti-affinity group.
39+
- `time_created` (String) Timestamp of when this anti-affinity group was created.
40+
- `time_modified` (String) Timestamp of when this anti-affinity group was last modified.
41+
42+
<a id="nestedatt--timeouts"></a>
43+
44+
### Nested Schema for `timeouts`
45+
46+
Optional:
47+
48+
- `read` (String, Default `10m`)
49+
50+
<a id="nestedobject--digest"></a>
51+
52+
### Nested Schema for `digest`
53+
54+
Read-Only:
55+
56+
- `type` (String) Digest type.
57+
- `value` (String) Digest type value.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
page_title: "oxide_anti_affinity_group Resource - terraform-provider-oxide"
3+
---
4+
5+
# oxide_anti_affinity_group (Resource)
6+
7+
This resource manages anti-affinity groups.
8+
9+
## Example Usage
10+
11+
```hcl
12+
resource "oxide_anti_affinity_group" "example" {
13+
project_id = "c1dee930-a8e4-11ed-afa1-0242ac120002"
14+
description = "a test anti-affinity group"
15+
name = "my-anti-affinty-group"
16+
policy = "allow"
17+
timeouts = {
18+
read = "1m"
19+
create = "3m"
20+
delete = "2m"
21+
update = "2m"
22+
}
23+
}
24+
```
25+
26+
## Schema
27+
28+
### Required
29+
30+
- `description` (String) Description for the anti-affinity group.
31+
- `name` (String) Name of the anti-affinity group.
32+
- `policy` (String) Affinity policy used to describe what to do when a request cannot be satisfied. Possible values are: `allow` or `fail`.
33+
- `project_id` (String) ID of the project that will contain the anti-affinity group.
34+
35+
### Optional
36+
37+
- `timeouts` (Attribute, Optional) (see [below for nested schema](#nestedatt--timeouts))
38+
39+
### Read-Only
40+
41+
- `id` (String) Unique, immutable, system-controlled identifier of the anti-affinity group.
42+
- `failure_domain` (String) Describes the scope of affinity for the purposes of co-location.
43+
- `time_created` (String) Timestamp of when this anti-affinity group was created.
44+
- `time_modified` (String) Timestamp of when this anti-affinity group was last modified.
45+
46+
<a id="nestedatt--timeouts"></a>
47+
48+
### Nested Schema for `timeouts`
49+
50+
Optional:
51+
52+
- `create` (String, Default `10m`)
53+
- `delete` (String, Default `10m`)
54+
- `read` (String, Default `10m`)
55+
- `update` (String, Default `10m`)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/hashicorp/terraform-plugin-log v0.9.0
1212
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1
1313
github.com/hashicorp/terraform-plugin-testing v1.12.0
14-
github.com/oxidecomputer/oxide.go v0.3.1-0.20250328231836-c8be65844352
14+
github.com/oxidecomputer/oxide.go v0.3.1-0.20250403205243-894605d0e70a
1515
github.com/stretchr/testify v1.10.0
1616
)
1717

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
136136
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
137137
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
138138
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
139-
github.com/oxidecomputer/oxide.go v0.3.1-0.20250328231836-c8be65844352 h1:C7+yo9PnkjVkS4UvhX0gMUQhzaBbS5L8WTsEraSdgyM=
140-
github.com/oxidecomputer/oxide.go v0.3.1-0.20250328231836-c8be65844352/go.mod h1:yNLdQdroM42/yDIFlCsLAR9PawAdeJZDgHdAx+wcywg=
139+
github.com/oxidecomputer/oxide.go v0.3.1-0.20250403205243-894605d0e70a h1:Zn3udDHSZA6zqrxm9m2gx1oRFpEBa44nM1U+FiYZbjY=
140+
github.com/oxidecomputer/oxide.go v0.3.1-0.20250403205243-894605d0e70a/go.mod h1:yNLdQdroM42/yDIFlCsLAR9PawAdeJZDgHdAx+wcywg=
141141
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
142142
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
143143
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
package provider
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
"github.com/hashicorp/terraform-plugin-framework-timeouts/datasource/timeouts"
12+
"github.com/hashicorp/terraform-plugin-framework/datasource"
13+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
"github.com/hashicorp/terraform-plugin-log/tflog"
16+
"github.com/oxidecomputer/oxide.go/oxide"
17+
)
18+
19+
var (
20+
_ datasource.DataSource = (*antiAffinityGroupDataSource)(nil)
21+
_ datasource.DataSourceWithConfigure = (*antiAffinityGroupDataSource)(nil)
22+
)
23+
24+
// NewAntiAffinityGroupDataSource initialises an anti-affinity group datasource
25+
func NewAntiAffinityGroupDataSource() datasource.DataSource {
26+
return &antiAffinityGroupDataSource{}
27+
}
28+
29+
type antiAffinityGroupDataSource struct {
30+
client *oxide.Client
31+
}
32+
33+
type antiAffinityGroupDataSourceModel struct {
34+
Description types.String `tfsdk:"description"`
35+
FailureDomain types.String `tfsdk:"failure_domain"`
36+
ID types.String `tfsdk:"id"`
37+
Name types.String `tfsdk:"name"`
38+
Policy types.String `tfsdk:"policy"`
39+
ProjectID types.String `tfsdk:"project_id"`
40+
TimeCreated types.String `tfsdk:"time_created"`
41+
TimeModified types.String `tfsdk:"time_modified"`
42+
Timeouts timeouts.Value `tfsdk:"timeouts"`
43+
ProjectName types.String `tfsdk:"project_name"`
44+
}
45+
46+
func (d *antiAffinityGroupDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
47+
resp.TypeName = "oxide_anti_affinity_group"
48+
}
49+
50+
// Configure adds the provider configured client to the data source.
51+
func (d *antiAffinityGroupDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
52+
if req.ProviderData == nil {
53+
return
54+
}
55+
56+
d.client = req.ProviderData.(*oxide.Client)
57+
}
58+
59+
func (d *antiAffinityGroupDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
60+
resp.Schema = schema.Schema{
61+
Attributes: map[string]schema.Attribute{
62+
"project_name": schema.StringAttribute{
63+
Required: true,
64+
Description: "Name of the project that contains the anti-affinity group.",
65+
},
66+
"name": schema.StringAttribute{
67+
Required: true,
68+
Description: "Name of the anti-affinity group.",
69+
},
70+
"project_id": schema.StringAttribute{
71+
Computed: true,
72+
Description: "ID of the project that contains the anti-affinity group.",
73+
},
74+
"description": schema.StringAttribute{
75+
Computed: true,
76+
Description: "Description for the anti-affinity group.",
77+
},
78+
"policy": schema.StringAttribute{
79+
Computed: true,
80+
Description: "Affinity policy used to describe what to do when a request cannot be satisfied.",
81+
},
82+
"failure_domain": schema.StringAttribute{
83+
Computed: true,
84+
Description: "Describes the scope of affinity for the purposes of co-location.",
85+
},
86+
"timeouts": timeouts.Attributes(ctx),
87+
"id": schema.StringAttribute{
88+
Computed: true,
89+
Description: "Unique, immutable, system-controlled identifier of the anti-affinity group.",
90+
},
91+
"time_created": schema.StringAttribute{
92+
Computed: true,
93+
Description: "Timestamp of when this anti-affinity group was created.",
94+
},
95+
"time_modified": schema.StringAttribute{
96+
Computed: true,
97+
Description: "Timestamp of when this anti-affinity group was last modified.",
98+
},
99+
},
100+
}
101+
}
102+
103+
func (d *antiAffinityGroupDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
104+
var state antiAffinityGroupDataSourceModel
105+
106+
// Read Terraform configuration data into the model
107+
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
108+
if resp.Diagnostics.HasError() {
109+
return
110+
}
111+
112+
readTimeout, diags := state.Timeouts.Read(ctx, defaultTimeout())
113+
resp.Diagnostics.Append(diags...)
114+
if resp.Diagnostics.HasError() {
115+
return
116+
}
117+
ctx, cancel := context.WithTimeout(ctx, readTimeout)
118+
defer cancel()
119+
120+
params := oxide.AntiAffinityGroupViewParams{
121+
AntiAffinityGroup: oxide.NameOrId(state.Name.ValueString()),
122+
Project: oxide.NameOrId(state.ProjectName.ValueString()),
123+
}
124+
antiAffinityGroup, err := d.client.AntiAffinityGroupView(ctx, params)
125+
if err != nil {
126+
resp.Diagnostics.AddError(
127+
"Unable to read anti-affinity group:",
128+
"API error: "+err.Error(),
129+
)
130+
return
131+
}
132+
tflog.Trace(ctx, fmt.Sprintf("read anti-affinity group with ID: %v", antiAffinityGroup.Id), map[string]any{"success": true})
133+
134+
state.Description = types.StringValue(antiAffinityGroup.Description)
135+
state.FailureDomain = types.StringValue(string(antiAffinityGroup.FailureDomain))
136+
state.ID = types.StringValue(antiAffinityGroup.Id)
137+
state.Name = types.StringValue(string(antiAffinityGroup.Name))
138+
state.Policy = types.StringValue(string(antiAffinityGroup.Policy))
139+
state.ProjectID = types.StringValue(antiAffinityGroup.ProjectId)
140+
state.TimeCreated = types.StringValue(antiAffinityGroup.TimeCreated.String())
141+
state.TimeModified = types.StringValue(antiAffinityGroup.TimeModified.String())
142+
143+
// Save state into Terraform state
144+
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
145+
if resp.Diagnostics.HasError() {
146+
return
147+
}
148+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
package provider
6+
7+
import (
8+
"fmt"
9+
"testing"
10+
11+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
12+
)
13+
14+
type dataSourceAntiAffinityGroupConfig struct {
15+
BlockName string
16+
Name string
17+
SupportBlockName string
18+
SupportBlockName2 string
19+
}
20+
21+
var dataSourceAntiAffinityGroupConfigTpl = `
22+
data "oxide_project" "{{.SupportBlockName}}" {
23+
name = "tf-acc-test"
24+
}
25+
26+
resource "oxide_anti_affinity_group" "{{.SupportBlockName2}}" {
27+
project_id = data.oxide_project.{{.SupportBlockName}}.id
28+
name = "{{.Name}}"
29+
description = "a group"
30+
policy = "allow"
31+
}
32+
33+
data "oxide_anti_affinity_group" "{{.BlockName}}" {
34+
project_name = "tf-acc-test"
35+
name = oxide_anti_affinity_group.{{.SupportBlockName2}}.name
36+
timeouts = {
37+
read = "1m"
38+
}
39+
}
40+
`
41+
42+
func TestAccCloudDataSourceAntiAffinityGroup_full(t *testing.T) {
43+
blockName := newBlockName("datasource-anti-affinity-group")
44+
resourceName := newResourceName()
45+
config, err := parsedAccConfig(
46+
dataSourceAntiAffinityGroupConfig{
47+
BlockName: blockName,
48+
SupportBlockName: newBlockName("support"),
49+
SupportBlockName2: newBlockName("support"),
50+
Name: resourceName,
51+
},
52+
dataSourceAntiAffinityGroupConfigTpl,
53+
)
54+
if err != nil {
55+
t.Errorf("error parsing config template data: %e", err)
56+
}
57+
58+
resource.ParallelTest(t, resource.TestCase{
59+
PreCheck: func() { testAccPreCheck(t) },
60+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(),
61+
Steps: []resource.TestStep{
62+
{
63+
Config: config,
64+
Check: checkDataSourceAntiAffinityGroup(
65+
fmt.Sprintf("data.oxide_anti_affinity_group.%s", blockName),
66+
resourceName,
67+
),
68+
},
69+
},
70+
})
71+
}
72+
73+
func checkDataSourceAntiAffinityGroup(dataName, keyName string) resource.TestCheckFunc {
74+
return resource.ComposeAggregateTestCheckFunc([]resource.TestCheckFunc{
75+
resource.TestCheckResourceAttrSet(dataName, "id"),
76+
resource.TestCheckResourceAttr(dataName, "name", keyName),
77+
resource.TestCheckResourceAttr(dataName, "description", "a group"),
78+
resource.TestCheckResourceAttr(dataName, "policy", "allow"),
79+
resource.TestCheckResourceAttr(dataName, "failure_domain", "sled"),
80+
resource.TestCheckResourceAttrSet(dataName, "project_id"),
81+
resource.TestCheckResourceAttrSet(dataName, "time_created"),
82+
resource.TestCheckResourceAttrSet(dataName, "time_modified"),
83+
resource.TestCheckResourceAttr(dataName, "timeouts.read", "1m"),
84+
}...)
85+
}

internal/provider/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ func (p *oxideProvider) Configure(ctx context.Context, req provider.ConfigureReq
161161
// DataSources defines the data sources implemented in the provider.
162162
func (p *oxideProvider) DataSources(_ context.Context) []func() datasource.DataSource {
163163
return []func() datasource.DataSource{
164+
NewAntiAffinityGroupDataSource,
164165
NewImageDataSource,
165166
NewImagesDataSource,
166167
NewInstanceExternalIPsDataSource,
@@ -179,6 +180,7 @@ func (p *oxideProvider) DataSources(_ context.Context) []func() datasource.DataS
179180
// Resources defines the resources implemented in the provider.
180181
func (p *oxideProvider) Resources(_ context.Context) []func() resource.Resource {
181182
return []func() resource.Resource{
183+
NewAntiAffinityGroupResource,
182184
NewDiskResource,
183185
NewImageResource,
184186
NewInstanceResource,

0 commit comments

Comments
 (0)