Skip to content

Commit 9e8465f

Browse files
add cockroach_blackout_window resource and cockroach_blackout_windows data source
This commit adds support for blackout windows via the `cockroach_blackout_window` resource. It also adds a `cockroach_blackout_windows` data source for listing blackout windows.
1 parent 33acaab commit 9e8465f

File tree

12 files changed

+1365
-0
lines changed

12 files changed

+1365
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Added support for configurable 30, 60, or 90 day patch upgrade deferrals in
1616
`cockroach_version_deferral` resource.
1717

18+
- Added support for creating blackout windows via the
19+
`cockroach_blackout_window` resource.
20+
21+
- Added `cockroach_blackout_windows` data source for listing blackout windows
22+
for a cluster
23+
1824
## [1.15.2] - 2025-10-16
1925

2026
### Fixed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "cockroach_blackout_windows Data Source - terraform-provider-cockroach"
4+
subcategory: ""
5+
description: |-
6+
Retrieve blackout windows defined for a CockroachDB Cloud cluster.
7+
---
8+
9+
# cockroach_blackout_windows (Data Source)
10+
11+
Retrieve blackout windows defined for a CockroachDB Cloud cluster.
12+
13+
## Example Usage
14+
15+
```terraform
16+
# List all blackout windows (upto 100)
17+
data "cockroach_blackout_windows" "all" {
18+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
19+
}
20+
21+
# Limit results and sort order
22+
data "cockroach_blackout_windows" "limited" {
23+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
24+
limit = 3
25+
sort_order = "DESC" # default is "ASC"
26+
}
27+
28+
# Pagination: fetch page 1, and then use the token for page 2
29+
data "cockroach_blackout_windows" "page_1" {
30+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
31+
limit = 2
32+
}
33+
34+
data "cockroach_blackout_windows" "page_2" {
35+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
36+
page = data.cockroach_blackout_windows.page_1.next_page
37+
}
38+
```
39+
40+
<!-- schema generated by tfplugindocs -->
41+
## Schema
42+
43+
### Required
44+
45+
- `cluster_id` (String) ID of the cluster to query for blackout windows.
46+
47+
### Optional
48+
49+
- `limit` (Number) Maximum number of blackout windows to return in a single response. Defaults to 100 when not set.
50+
- `page` (String) A pagination token used to request the next page of results. This value should come from the `next_page` attribute of a previous data source call.
51+
- `sort_order` (String) Specifies the sort direction for the returned results, which are ordered based on the `start_time` field. Use `ASC` for ascending or `DESC` for descending order. Defaults to `ASC`.
52+
53+
### Read-Only
54+
55+
- `blackout_windows` (Attributes List) List of blackout windows returned by the API. (see [below for nested schema](#nestedatt--blackout_windows))
56+
- `next_page` (String) Pagination token for the next page of results returned by the API. Pass this value into the `page` argument in a subsequent data source call to retrieve the next set of blackout windows. Empty if there are no more pages.
57+
58+
<a id="nestedatt--blackout_windows"></a>
59+
### Nested Schema for `blackout_windows`
60+
61+
Read-Only:
62+
63+
- `cluster_id` (String) ID of the cluster the blackout window belongs to.
64+
- `end_time` (String) UTC end time in RFC3339 format (e.g. `2025-03-18T09:00:00Z`).
65+
- `id` (String) Unique blackout window identifier.
66+
- `start_time` (String) UTC start time in RFC3339 format (e.g. `2025-03-15T09:00:00Z`).

docs/resources/blackout_window.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "cockroach_blackout_window Resource - terraform-provider-cockroach"
4+
subcategory: ""
5+
description: |-
6+
Blackout windows schedule a period of up to 14 days for an ADVANCED cluster to block high-risk operations that impact SQL availability or require CRDB pod restarts.
7+
Two consecutive maintenance windows cannot be covered by blackout windows.
8+
---
9+
10+
# cockroach_blackout_window (Resource)
11+
12+
Blackout windows schedule a period of up to 14 days for an ADVANCED cluster to block high-risk operations that impact SQL availability or require CRDB pod restarts.
13+
14+
Two consecutive maintenance windows cannot be covered by blackout windows.
15+
16+
## Example Usage
17+
18+
```terraform
19+
# This example assumes you already have an ADVANCED cluster and
20+
# an active maintenance window on that cluster.
21+
22+
resource "cockroach_blackout_window" "example" {
23+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
24+
start_time = "2025-03-15T09:00:00Z"
25+
end_time = "2025-03-18T09:00:00Z"
26+
}
27+
```
28+
29+
<!-- schema generated by tfplugindocs -->
30+
## Schema
31+
32+
### Required
33+
34+
- `cluster_id` (String) ID of the cluster the blackout window applies to.
35+
36+
### Optional
37+
38+
- `end_time` (String) The UTC end time for the blackout window in RFC3339 format (e.g. `2025-03-18T09:00:00Z`). Must fall within 14 days of `start_time` and no later than three months from now.
39+
- `start_time` (String) The UTC start time for the blackout window in RFC3339 format (e.g. `2025-03-15T09:00:00Z`). Must be scheduled at least seven days in advance.
40+
41+
### Read-Only
42+
43+
- `id` (String) Unique blackout window identifier returned by the API.
44+
45+
## Import
46+
47+
Import is supported using the following syntax:
48+
49+
```shell
50+
# format : terraform import <resource> <cluster_id>:<blackout_window_id>
51+
terraform import cockroach_blackout_window.example d9bf7d1a-6e18-446a-cbd0-6a0aee8a9e18:ea131d23-1eg7-99f0-b79c-a42ee26r60re
52+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# List all blackout windows (upto 100)
2+
data "cockroach_blackout_windows" "all" {
3+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
4+
}
5+
6+
# Limit results and sort order
7+
data "cockroach_blackout_windows" "limited" {
8+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
9+
limit = 3
10+
sort_order = "DESC" # default is "ASC"
11+
}
12+
13+
# Pagination: fetch page 1, and then use the token for page 2
14+
data "cockroach_blackout_windows" "page_1" {
15+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
16+
limit = 2
17+
}
18+
19+
data "cockroach_blackout_windows" "page_2" {
20+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
21+
page = data.cockroach_blackout_windows.page_1.next_page
22+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# format : terraform import <resource> <cluster_id>:<blackout_window_id>
2+
terraform import cockroach_blackout_window.example d9bf7d1a-6e18-446a-cbd0-6a0aee8a9e18:ea131d23-1eg7-99f0-b79c-a42ee26r60re
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This example assumes you already have an ADVANCED cluster and
2+
# an active maintenance window on that cluster.
3+
4+
resource "cockroach_blackout_window" "example" {
5+
cluster_id = "123e4567-e89b-12d3-a456-426614174000"
6+
start_time = "2025-03-15T09:00:00Z"
7+
end_time = "2025-03-18T09:00:00Z"
8+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"github.com/cockroachdb/cockroach-cloud-sdk-go/v6/pkg/client"
10+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
11+
"github.com/hashicorp/terraform-plugin-framework/datasource"
12+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
13+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
)
16+
17+
type blackoutWindowDataSource struct {
18+
provider *provider
19+
}
20+
21+
func NewBlackoutWindowDataSource() datasource.DataSource {
22+
return &blackoutWindowDataSource{}
23+
}
24+
25+
func (d *blackoutWindowDataSource) Schema(
26+
_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse,
27+
) {
28+
resp.Schema = schema.Schema{
29+
Description: "Retrieve blackout windows defined for a CockroachDB Cloud cluster.",
30+
Attributes: map[string]schema.Attribute{
31+
"cluster_id": schema.StringAttribute{
32+
MarkdownDescription: "ID of the cluster to query for blackout windows.",
33+
Required: true,
34+
Validators: uuidValidator,
35+
},
36+
"page": schema.StringAttribute{
37+
Optional: true,
38+
MarkdownDescription: "A pagination token used to request the next page of results. This value should come from the `next_page` attribute of a previous data source call.",
39+
},
40+
"sort_order": schema.StringAttribute{
41+
Optional: true,
42+
MarkdownDescription: "Specifies the sort direction for the returned results, which are ordered based on the `start_time` field. Use `ASC` for ascending or `DESC` for descending order. Defaults to `ASC`.",
43+
Validators: []validator.String{stringvalidator.OneOf("ASC", "DESC")},
44+
},
45+
"limit": schema.Int32Attribute{
46+
Optional: true,
47+
MarkdownDescription: "Maximum number of blackout windows to return in a single response. Defaults to 100 when not set.",
48+
},
49+
"next_page": schema.StringAttribute{
50+
Computed: true,
51+
MarkdownDescription: "Pagination token for the next page of results returned by the API. Pass this value into the `page` argument in a subsequent data source call to retrieve the next set of blackout windows. Empty if there are no more pages.",
52+
},
53+
"blackout_windows": schema.ListNestedAttribute{
54+
Computed: true,
55+
MarkdownDescription: "List of blackout windows returned by the API.",
56+
NestedObject: schema.NestedAttributeObject{
57+
Attributes: map[string]schema.Attribute{
58+
"cluster_id": schema.StringAttribute{
59+
Computed: true,
60+
MarkdownDescription: "ID of the cluster the blackout window belongs to.",
61+
},
62+
"id": schema.StringAttribute{
63+
Computed: true,
64+
MarkdownDescription: "Unique blackout window identifier.",
65+
},
66+
"start_time": schema.StringAttribute{
67+
Computed: true,
68+
MarkdownDescription: "UTC start time in RFC3339 format (e.g. `2025-03-15T09:00:00Z`).",
69+
},
70+
"end_time": schema.StringAttribute{
71+
Computed: true,
72+
MarkdownDescription: "UTC end time in RFC3339 format (e.g. `2025-03-18T09:00:00Z`).",
73+
},
74+
},
75+
},
76+
},
77+
},
78+
}
79+
}
80+
81+
func (d *blackoutWindowDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
82+
resp.TypeName = req.ProviderTypeName + "_blackout_windows"
83+
}
84+
85+
func (d *blackoutWindowDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
86+
if req.ProviderData == nil {
87+
return
88+
}
89+
var ok bool
90+
if d.provider, ok = req.ProviderData.(*provider); !ok {
91+
resp.Diagnostics.AddError(
92+
"Internal provider error",
93+
fmt.Sprintf("Error in Configure: expected %T but got %T", provider{}, req.ProviderData),
94+
)
95+
}
96+
}
97+
98+
func (d *blackoutWindowDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
99+
if d.provider == nil || !d.provider.configured {
100+
addConfigureProviderErr(&resp.Diagnostics)
101+
return
102+
}
103+
104+
var listConfig BlackoutWindowList
105+
diags := req.Config.Get(ctx, &listConfig)
106+
107+
resp.Diagnostics.Append(diags...)
108+
if resp.Diagnostics.HasError() {
109+
resp.Diagnostics.AddWarning("Error loading the blackout window list", "")
110+
return
111+
}
112+
113+
clusterID := listConfig.ClusterID.ValueString()
114+
115+
listBlackoutWindowsOptions := &client.ListBlackoutWindowsOptions{}
116+
117+
if IsKnown(listConfig.Limit) {
118+
listBlackoutWindowsOptions.PaginationLimit = listConfig.Limit.ValueInt32Pointer()
119+
}
120+
121+
if IsKnown(listConfig.Page) {
122+
page := strings.TrimSpace(listConfig.Page.ValueString())
123+
if page != "" {
124+
listBlackoutWindowsOptions.PaginationPage = &page
125+
}
126+
}
127+
128+
if IsKnown(listConfig.SortOrder) {
129+
sortOrder := strings.ToUpper(strings.TrimSpace(listConfig.SortOrder.ValueString()))
130+
if sortOrder != "" {
131+
listBlackoutWindowsOptions.PaginationSortOrder = &sortOrder
132+
listConfig.SortOrder = types.StringValue(sortOrder)
133+
}
134+
}
135+
136+
traceAPICall("ListBlackoutWindows")
137+
listResp, _, err := d.provider.service.ListBlackoutWindows(ctx, clusterID, listBlackoutWindowsOptions)
138+
if err != nil || listResp == nil {
139+
resp.Diagnostics.AddError(
140+
"Error listing blackout windows",
141+
fmt.Sprintf("Unexpected error retrieving blackout windows: %s", formatAPIErrorMessage(err)),
142+
)
143+
return
144+
}
145+
146+
listConfig.BlackoutWindows = make([]BlackoutWindow, 0)
147+
if listResp.BlackoutWindows != nil {
148+
for _, window := range *listResp.BlackoutWindows {
149+
listConfig.BlackoutWindows = append(listConfig.BlackoutWindows, BlackoutWindow{
150+
ClusterID: types.StringValue(window.GetClusterId()),
151+
ID: types.StringValue(window.GetId()),
152+
StartTime: types.StringValue(window.GetStartTime().UTC().Format(time.RFC3339)),
153+
EndTime: types.StringValue(window.GetEndTime().UTC().Format(time.RFC3339)),
154+
})
155+
}
156+
}
157+
158+
if listResp.Pagination != nil && listResp.Pagination.NextPage != nil && *listResp.Pagination.NextPage != "" {
159+
listConfig.NextPage = types.StringValue(*listResp.Pagination.NextPage)
160+
} else {
161+
listConfig.NextPage = types.StringNull()
162+
}
163+
164+
diags = resp.State.Set(ctx, listConfig)
165+
resp.Diagnostics.Append(diags...)
166+
}

0 commit comments

Comments
 (0)