Skip to content

Commit 0262d28

Browse files
Merge pull request #2227 from linode/dev
Release v3.8.0
2 parents 2b35254 + 8d1c0a1 commit 0262d28

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1027
-150
lines changed

.github/dependabot.yml

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,3 @@ updates:
2020
directory: "/"
2121
schedule:
2222
interval: "monthly"
23-
24-
# extended-support/v2
25-
- package-ecosystem: "gomod"
26-
target-branch: extended-support/v2
27-
directory: "/"
28-
schedule:
29-
interval: "monthly"
30-
ignore:
31-
- dependency-name: "github.com/linode/terraform-provider-linode/linode"
32-
- package-ecosystem: "gomod"
33-
target-branch: extended-support/v2
34-
directory: "/tools"
35-
schedule:
36-
interval: "monthly"
37-
- package-ecosystem: "github-actions"
38-
target-branch: extended-support/v2
39-
directory: "/"
40-
schedule:
41-
interval: "monthly"

.github/workflows/integration_tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787

8888
- name: Upload Test Report as Artifact
8989
if: always()
90-
uses: actions/upload-artifact@v5
90+
uses: actions/upload-artifact@v6
9191
with:
9292
name: test-report-${{ matrix.user }}
9393
if-no-files-found: ignore
@@ -174,7 +174,7 @@ jobs:
174174
run: pip3 install requests wheel boto3==1.35.99
175175

176176
- name: Download test report
177-
uses: actions/download-artifact@v6
177+
uses: actions/download-artifact@v7
178178

179179
- name: Get .xml reports from separate Artifacts into root folder
180180
run: rsync -av test-report-USER_*/* .

AGENTS.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Terraform Provider for Linode - AI Agent Instructions
2+
3+
## Architecture Overview
4+
5+
This is a Terraform provider that uses **both** SDKv2 and Plugin Framework patterns (muxed together). Resources/data sources live under `linode/<resource-name>/` with each package being self-contained.
6+
7+
- **SDKv2 resources** (legacy): `linode/instance/`, `linode/domain/`, `linode/lke/` - use `resource.go`, `datasource.go`
8+
- **Plugin Framework resources** (preferred for new work): `linode/vpc/`, `linode/volume/`, `linode/vpcsubnet/` - use `framework_resource.go`, `framework_datasource.go`, `framework_models.go`
9+
- **Provider registration**: SDKv2 in `linode/provider.go`, Framework in `linode/framework_provider.go`
10+
- **Shared utilities**: `linode/helper/` - conversion functions, base resource/datasource, plan modifiers
11+
12+
## Framework Resource Structure (New Resources)
13+
14+
Each Framework resource package follows this pattern:
15+
16+
```
17+
linode/<resource-name>/
18+
├── framework_resource.go # CRUD operations
19+
├── framework_datasource.go # Data source Read
20+
├── framework_models.go # Terraform state models with Flatten/CopyFrom methods
21+
├── framework_schema_resource.go # Resource schema definition
22+
├── framework_schema_datasource.go # Data source schema definition
23+
├── resource_test.go # Integration tests
24+
├── datasource_test.go # Data source integration tests
25+
├── tmpl/ # Test templates
26+
│ ├── template.go # Go functions returning HCL configs
27+
│ └── *.gotf # HCL template files
28+
```
29+
30+
### Key Model Patterns
31+
32+
Models must implement:
33+
- `FlattenXxx(ctx, apiObject, preserveKnown)` - Converts Linode API response to Terraform state
34+
- `CopyFrom(ctx, other, preserveKnown)` - Copies values between model instances for updates
35+
36+
Use `helper.KeepOrUpdateValue()`, `helper.KeepOrUpdateString()`, `helper.KeepOrUpdateInt64()` to handle `preserveKnown` flag which prevents overwriting known plan values with computed values.
37+
38+
## Test Commands
39+
40+
```bash
41+
# Run all tests for a package
42+
make TEST_SUITE="vpcsubnet" test-int
43+
44+
# Run a specific test
45+
make PKG_NAME="volume" TEST_CASE="TestAccResourceVolume_basic" test-int
46+
47+
# Run unit tests only
48+
make test-unit
49+
50+
# Run unit tests for a specific package
51+
make PKG_NAME="instance" test-unit
52+
```
53+
54+
**Important**: Set `LINODE_TOKEN` environment variable or use `.env` file. Tests create real resources (costs money).
55+
56+
## Test Template Pattern
57+
58+
Tests use `.gotf` template files with Go text/template syntax:
59+
60+
```go
61+
// In tmpl/template.go
62+
func Basic(t testing.TB, label, region string) string {
63+
return acceptance.ExecuteTemplate(t, "resource_basic", TemplateData{
64+
Label: label, Region: region,
65+
})
66+
}
67+
```
68+
69+
```hcl
70+
// In tmpl/basic.gotf
71+
{{ define "resource_basic" }}
72+
resource "linode_example" "foobar" {
73+
label = "{{.Label}}"
74+
region = "{{.Region}}"
75+
}
76+
{{ end }}
77+
```
78+
79+
## Build Tags
80+
81+
- `//go:build integration` or `//go:build <resource-name>` - Integration tests (require API token)
82+
- `//go:build unit` - Unit tests (no API calls)
83+
84+
## Helper Functions Reference
85+
86+
| Function | Purpose |
87+
|----------|---------|
88+
| `helper.NewBaseResource()` | Creates base Framework resource with common config |
89+
| `helper.KeepOrUpdateValue()` | Conditionally preserves known values during refresh |
90+
| `helper.FrameworkSafeInt64ToInt()` | Safe int64→int conversion with diagnostics |
91+
| `helper.MapSlice()` | Transforms slices with a mapping function |
92+
| `acceptance.GetRandomRegionWithCaps()` | Gets random region with required capabilities |
93+
| `acceptance.ExecuteTemplate()` | Renders HCL test templates |
94+
95+
## Common Workflows
96+
97+
**Adding a new Framework resource:**
98+
1. Create package under `linode/<resource-name>/`
99+
2. Define schema in `framework_schema_resource.go`
100+
3. Define models in `framework_models.go` with `Flatten*` and `CopyFrom` methods
101+
4. Implement CRUD in `framework_resource.go`
102+
5. Register in `linode/framework_provider.go` Resources() method
103+
6. Add tests with `tmpl/` directory
104+
7. Add docs in `docs/resources/<resource>.md`
105+
106+
**Debugging tests:**
107+
- `TF_LOG_PROVIDER=DEBUG` - Provider logging
108+
- `TF_LOG_PROVIDER_LINODE_REQUESTS=DEBUG` - API request logging
109+
- `TF_SCHEMA_PANIC_ON_ERROR=1` - Force panic on schema errors
110+
111+
## Linode API Client
112+
113+
Uses `github.com/linode/linodego` client. Access via:
114+
- SDKv2: `meta.(*helper.ProviderMeta).Client`
115+
- Framework: `r.Meta.Client`
116+
117+
## Code Style
118+
119+
- Use `golangci-lint fmt` for code formatting (run `make format`), or `gofmt -w` if unavailable
120+
- Use `tflog.Debug(ctx, ...)` for logging in resources
121+
- Prefer Framework over SDKv2 for new resources
122+
- Unit test files use `*_unit_test.go` naming with `//go:build unit` tag
123+
124+
## Go Idioms
125+
126+
**Sets using maps (Go 1.23+):**
127+
Use `helper.StringSet` and `helper.ExistsInSet` for set operations, then extract keys with `slices.Collect(maps.Keys())`:
128+
129+
```go
130+
import (
131+
"maps"
132+
"slices"
133+
"github.com/linode/terraform-provider-linode/v3/linode/helper"
134+
)
135+
136+
// Create a set
137+
regionSet := make(helper.StringSet)
138+
for _, endpoint := range endpoints {
139+
regionSet[endpoint.Region] = helper.ExistsInSet
140+
}
141+
142+
// Extract keys as a slice (Go 1.23+)
143+
regions := slices.Collect(maps.Keys(regionSet))
144+
```
145+
146+
This is preferred over the manual loop pattern:
147+
```go
148+
// Avoid this verbose pattern
149+
regions := make([]string, 0, len(regionSet))
150+
for region := range regionSet {
151+
regions = append(regions, region)
152+
}
153+
```

docs/data-sources/instances.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ Each Linode instance will be stored in the `instances` attribute and will export
7979

8080
* `capabilities` - A list of capabilities of this Linode instance.
8181

82+
* `locks` - A list of locks applied to this Linode.
83+
8284
* `private_ip` - If true, the Linode has private networking enabled, allowing use of the 192.168.128.0/17 network within the Linode's region.
8385

8486
* `alerts.0.cpu` - The percentage of CPU usage required to trigger an alert. If the average CPU usage over two hours exceeds this value, we'll send you an alert. If this is set to 0, the alert is disabled.

docs/data-sources/lke_cluster.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ In addition to all arguments above, the following attributes are exported:
6161

6262
* `label` - The label of the Node Pool.
6363

64+
* `firewall_id` - The ID of the firewall associated with the Node Pool.
65+
6466
* `type` - The linode type for all of the nodes in the Node Pool. See all node types [here](https://api.linode.com/v4/linode/types).
6567

6668
* `count` - The number of nodes in the Node Pool.

docs/resources/instance.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ The following arguments are supported:
154154

155155
* `tags` - (Optional) A list of tags applied to this object. Tags are case-insensitive and are for organizational purposes only.
156156

157+
* `locks` - (Read-Only) A list of locks applied to this Linode.
158+
157159
* `maintenance_policy` - (Optional) The maintenance policy of this Linode instance. Examples are `"linode/migrate"` and `"linode/power_off_on"`. Defaults to the default maintenance policy of the account. (**Note: v4beta only.**)
158160

159161
* `private_ip` - (Optional) If true, the created Linode will have private networking enabled, allowing use of the 192.168.128.0/17 network within the Linode's region. It can be enabled on an existing Linode but it can't be disabled.
@@ -409,6 +411,8 @@ This Linode Instance resource exports the following attributes:
409411

410412
* `lke_cluster_id` - If applicable, the ID of the LKE cluster this instance is a part of.
411413

414+
* `locks` - A list of locks applied to this Linode.
415+
412416
* `specs.0.disk` - The amount of storage space, in GB. this Linode has access to. A typical Linode will divide this space between a primary disk with an image deployed to it, and a swap disk, usually 512 MB. This is the default configuration created when deploying a Linode with an image through POST /linode/instances.
413417

414418
* `specs.0.memory` - The amount of RAM, in MB, this Linode has access to. Typically a Linode will choose to boot with all of its available RAM, but this can be configured in a Config profile.

docs/resources/lke_cluster.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,24 @@ resource "linode_lke_cluster" "my-cluster" {
118118
}
119119
```
120120

121+
Creating an LKE cluster with existing firewall on a node pool:
122+
123+
```terraform
124+
resource "linode_lke_cluster" "my-cluster" {
125+
label = "my-cluster"
126+
k8s_version = "1.32"
127+
region = "us-central"
128+
tags = ["prod"]
129+
130+
pool {
131+
type = "g6-standard-2"
132+
count = 2
133+
label = "db-pool"
134+
firewall_id = 12345
135+
}
136+
}
137+
```
138+
121139
Creating an LKE cluster with node pool labels:
122140

123141
```terraform
@@ -187,6 +205,8 @@ The following arguments are supported in the `pool` specification block:
187205

188206
* `label` - (Optional) A label for the Node Pool. If not provided, it defaults to empty string.
189207

208+
* `firewall_id` - (Optional) The ID of the firewall to associate with this node pool. If not provided, default firewall will be associated.
209+
190210
* `labels` - (Optional) A map of key/value pairs to apply to all nodes in the pool. Labels are used to identify and organize Kubernetes resources within your cluster.
191211

192212
* `tags` - (Optional) A set of tags applied to this node pool. Tags can be used to flag node pools as externally managed. See [Externally Managed Node Pools](#externally-managed-node-pools) for more details.

docs/resources/lke_node_pool.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ resource "linode_lke_node_pool" "my-pool" {
3838
}
3939
```
4040

41+
Creating a basic LKE Node with firewall:
42+
43+
```terraform
44+
resource "linode_lke_node_pool" "my-pool" {
45+
cluster_id = 150003
46+
type = "g6-standard-2"
47+
firewall_id = 12345
48+
node_count = 3
49+
}
50+
```
51+
4152
Creating an LKE Node Pool with autoscaler:
4253

4354
```terraform
@@ -104,6 +115,8 @@ The following arguments are supported:
104115

105116
* `label` - (Optional) A label for the Node Pool. If not provided, it defaults to empty string.
106117

118+
* `firewall_id` - (Optional) The ID of the firewall to associate with this node pool. If not provided, default firewall will be associated.
119+
107120
* `labels` - (Optional) A map attribute containing key-value pairs to be added as labels to nodes in the node pool. Labels help classify your nodes and to easily select subsets of objects. To learn more, review [Add Labels and Taints to your LKE Node Pools](https://www.linode.com/docs/products/compute/kubernetes/guides/deploy-and-manage-cluster-with-the-linode-api/#add-labels-and-taints-to-your-lke-node-pools).
108121

109122
* `k8s_version` - (Optional) The k8s version of the nodes in this node pool. For LKE enterprise only and may not currently available to all users even under v4beta.

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ require (
1717
github.com/hashicorp/go-cty v1.5.0
1818
github.com/hashicorp/go-hclog v1.6.3
1919
github.com/hashicorp/go-version v1.7.0
20-
github.com/hashicorp/terraform-plugin-framework v1.16.1
20+
github.com/hashicorp/terraform-plugin-framework v1.17.0
2121
github.com/hashicorp/terraform-plugin-framework-nettypes v0.3.0
2222
github.com/hashicorp/terraform-plugin-framework-timeouts v0.7.0
2323
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0
2424
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0
2525
github.com/hashicorp/terraform-plugin-go v0.29.0
26-
github.com/hashicorp/terraform-plugin-log v0.9.0
26+
github.com/hashicorp/terraform-plugin-log v0.10.0
2727
github.com/hashicorp/terraform-plugin-mux v0.21.0
2828
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1
29-
github.com/hashicorp/terraform-plugin-testing v1.13.3
29+
github.com/hashicorp/terraform-plugin-testing v1.14.0
3030
github.com/linode/linodego v1.62.0
3131
github.com/linode/linodego/k8s v1.25.2
3232
github.com/stretchr/testify v1.11.1
@@ -75,8 +75,8 @@ require (
7575
github.com/hashicorp/hc-install v0.9.2 // indirect
7676
github.com/hashicorp/hcl/v2 v2.24.0 // indirect
7777
github.com/hashicorp/logutils v1.0.0 // indirect
78-
github.com/hashicorp/terraform-exec v0.23.1 // indirect
79-
github.com/hashicorp/terraform-json v0.27.1 // indirect
78+
github.com/hashicorp/terraform-exec v0.24.0 // indirect
79+
github.com/hashicorp/terraform-json v0.27.2 // indirect
8080
github.com/hashicorp/terraform-registry-address v0.4.0 // indirect
8181
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
8282
github.com/hashicorp/yamux v0.1.2 // indirect

go.sum

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,12 @@ github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQx
141141
github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=
142142
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
143143
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
144-
github.com/hashicorp/terraform-exec v0.23.1 h1:diK5NSSDXDKqHEOIQefBMu9ny+FhzwlwV0xgUTB7VTo=
145-
github.com/hashicorp/terraform-exec v0.23.1/go.mod h1:e4ZEg9BJDRaSalGm2z8vvrPONt0XWG0/tXpmzYTf+dM=
146-
github.com/hashicorp/terraform-json v0.27.1 h1:zWhEracxJW6lcjt/JvximOYyc12pS/gaKSy/wzzE7nY=
147-
github.com/hashicorp/terraform-json v0.27.1/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE=
148-
github.com/hashicorp/terraform-plugin-framework v1.16.1 h1:1+zwFm3MEqd/0K3YBB2v9u9DtyYHyEuhVOfeIXbteWA=
149-
github.com/hashicorp/terraform-plugin-framework v1.16.1/go.mod h1:0xFOxLy5lRzDTayc4dzK/FakIgBhNf/lC4499R9cV4Y=
144+
github.com/hashicorp/terraform-exec v0.24.0 h1:mL0xlk9H5g2bn0pPF6JQZk5YlByqSqrO5VoaNtAf8OE=
145+
github.com/hashicorp/terraform-exec v0.24.0/go.mod h1:lluc/rDYfAhYdslLJQg3J0oDqo88oGQAdHR+wDqFvo4=
146+
github.com/hashicorp/terraform-json v0.27.2 h1:BwGuzM6iUPqf9JYM/Z4AF1OJ5VVJEEzoKST/tRDBJKU=
147+
github.com/hashicorp/terraform-json v0.27.2/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE=
148+
github.com/hashicorp/terraform-plugin-framework v1.17.0 h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY=
149+
github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0=
150150
github.com/hashicorp/terraform-plugin-framework-nettypes v0.3.0 h1:cEiRvdFAhFnivRm9JI/8l2g8oruzkioUAwItkEM7bmU=
151151
github.com/hashicorp/terraform-plugin-framework-nettypes v0.3.0/go.mod h1:SDIm7W2x3Bs9otNC0ysbaSQ7H4H/EPimoACTy+7Z9rU=
152152
github.com/hashicorp/terraform-plugin-framework-timeouts v0.7.0 h1:jblRy1PkLfPm5hb5XeMa3tezusnMRziUGqtT5epSYoI=
@@ -157,14 +157,14 @@ github.com/hashicorp/terraform-plugin-framework-validators v0.19.0 h1:Zz3iGgzxe/
157157
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0/go.mod h1:GBKTNGbGVJohU03dZ7U8wHqc2zYnMUawgCN+gC0itLc=
158158
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
159159
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
160-
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
161-
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
160+
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
161+
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
162162
github.com/hashicorp/terraform-plugin-mux v0.21.0 h1:QsEYnzSD2c3zT8zUrUGqaFGhV/Z8zRUlU7FY3ZPJFfw=
163163
github.com/hashicorp/terraform-plugin-mux v0.21.0/go.mod h1:Qpt8+6AD7NmL0DS7ASkN0EXpDQ2J/FnnIgeUr1tzr5A=
164164
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 h1:mlAq/OrMlg04IuJT7NpefI1wwtdpWudnEmjuQs04t/4=
165165
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1/go.mod h1:GQhpKVvvuwzD79e8/NZ+xzj+ZpWovdPAe8nfV/skwNU=
166-
github.com/hashicorp/terraform-plugin-testing v1.13.3 h1:QLi/khB8Z0a5L54AfPrHukFpnwsGL8cwwswj4RZduCo=
167-
github.com/hashicorp/terraform-plugin-testing v1.13.3/go.mod h1:WHQ9FDdiLoneey2/QHpGM/6SAYf4A7AZazVg7230pLE=
166+
github.com/hashicorp/terraform-plugin-testing v1.14.0 h1:5t4VKrjOJ0rg0sVuSJ86dz5K7PHsMO6OKrHFzDBerWA=
167+
github.com/hashicorp/terraform-plugin-testing v1.14.0/go.mod h1:1qfWkecyYe1Do2EEOK/5/WnTyvC8wQucUkkhiGLg5nk=
168168
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
169169
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
170170
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=

0 commit comments

Comments
 (0)