Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit eede862

Browse files
benPearce1domenicsim1HuyPhanNguyen
authored
feat: deployment freezes (#822)
Co-authored-by: domenicsim1 <domenic.simone@octopus.com> Co-authored-by: Huy Nguyen <huy.nguyen@octopus.com>
1 parent 1566f96 commit eede862

19 files changed

+1044
-23
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "octopusdeploy_deployment_freezes Data Source - terraform-provider-octopusdeploy"
4+
subcategory: ""
5+
description: |-
6+
Provides information about deployment freezes
7+
---
8+
9+
# octopusdeploy_deployment_freezes (Data Source)
10+
11+
Provides information about deployment freezes
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Optional
19+
20+
- `environment_ids` (List of String) A filter to search by a list of environment IDs
21+
- `ids` (List of String) A filter to search by a list of IDs.
22+
- `include_complete` (Boolean) Include deployment freezes that completed, default is true
23+
- `partial_name` (String) A filter to search by a partial name.
24+
- `project_ids` (List of String) A filter to search by a list of project IDs
25+
- `skip` (Number) A filter to specify the number of items to skip in the response.
26+
- `status` (String) Filter by the status of the deployment freeze, value values are Expired, Active, Scheduled (case-insensitive)
27+
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
28+
29+
### Read-Only
30+
31+
- `deployment_freezes` (Attributes List) (see [below for nested schema](#nestedatt--deployment_freezes))
32+
- `id` (String) The unique ID for this resource.
33+
34+
<a id="nestedatt--deployment_freezes"></a>
35+
### Nested Schema for `deployment_freezes`
36+
37+
Read-Only:
38+
39+
- `end` (String) The end time of the freeze
40+
- `id` (String) The unique ID for this resource.
41+
- `name` (String) The name of this resource.
42+
- `project_environment_scope` (Map of List of String) The project environment scope of the deployment freeze
43+
- `start` (String) The start time of the freeze
44+
45+
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "octopusdeploy_deployment_freeze Resource - terraform-provider-octopusdeploy"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# octopusdeploy_deployment_freeze (Resource)
10+
11+
12+
13+
## Example Usage
14+
15+
```terraform
16+
# basic freeze with no project scopes
17+
resource "octopusdeploy_deployment_freeze" "freeze" {
18+
name = "Xmas"
19+
start = "2024-12-25T00:00:00+10:00"
20+
end = "2024-12-27T00:00:00+08:00"
21+
}
22+
23+
# Freeze with different timezones and single project/environment scope
24+
resource "octopusdeploy_deployment_freeze" "freeze" {
25+
name = "Xmas"
26+
start = "2024-12-25T00:00:00+10:00"
27+
end = "2024-12-27T00:00:00+08:00"
28+
}
29+
30+
resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
31+
deploymentfreeze_id= octopusdeploy_deployment_freeze.freeze.id
32+
project_id = "Projects-123"
33+
environment_ids = [ "Environments-123", "Environments-456" ]
34+
}
35+
36+
# Freeze with ids sourced from resources and datasources. Projects can be sourced from different spaces, a single scope can only reference projects and environments from the same space.
37+
resource "octopusdeploy_deployment_freeze" "freeze" {
38+
name = "End of financial year shutdown"
39+
start = "2025-06-30T00:00:00+10:00"
40+
end = "2025-07-02T00:00:00+10:00"
41+
}
42+
43+
resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
44+
deploymentfreeze_id = octopusdeploy_deployment_freeze.freeze.id
45+
project_id = resource.octopusdeploy_project.project1.id
46+
environment_ids = [resource.octopusdeploy_environment.production.id]
47+
}
48+
49+
resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
50+
deploymentfreeze_id = octopusdeploy_deployment_freeze.freeze.id
51+
project_id = data.octopusdeploy_projects.second_project.projects[0].id
52+
environment_ids = [ data.octopusdeploy_environments.default_environment.environments[0].id ]
53+
}
54+
```
55+
56+
<!-- schema generated by tfplugindocs -->
57+
## Schema
58+
59+
### Required
60+
61+
- `end` (String) The end time of the freeze, must be RFC3339 format
62+
- `name` (String) The name of this resource.
63+
- `start` (String) The start time of the freeze, must be RFC3339 format
64+
65+
### Read-Only
66+
67+
- `id` (String) The unique ID for this resource.
68+
69+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "octopusdeploy_deployment_freeze_project Resource - terraform-provider-octopusdeploy"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# octopusdeploy_deployment_freeze_project (Resource)
10+
11+
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Required
19+
20+
- `deploymentfreeze_id` (String) The deployment freeze ID associated with this freeze scope.
21+
- `project_id` (String) The project ID associated with this freeze scope.
22+
23+
### Optional
24+
25+
- `environment_ids` (List of String) The environment IDs associated with this project deployment freeze scope.
26+
27+
### Read-Only
28+
29+
- `id` (String) The unique ID for this resource.
30+
31+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# basic freeze with no project scopes
2+
resource "octopusdeploy_deployment_freeze" "freeze" {
3+
name = "Xmas"
4+
start = "2024-12-25T00:00:00+10:00"
5+
end = "2024-12-27T00:00:00+08:00"
6+
}
7+
8+
# Freeze with different timezones and single project/environment scope
9+
resource "octopusdeploy_deployment_freeze" "freeze" {
10+
name = "Xmas"
11+
start = "2024-12-25T00:00:00+10:00"
12+
end = "2024-12-27T00:00:00+08:00"
13+
}
14+
15+
resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
16+
deploymentfreeze_id= octopusdeploy_deployment_freeze.freeze.id
17+
project_id = "Projects-123"
18+
environment_ids = [ "Environments-123", "Environments-456" ]
19+
}
20+
21+
# Freeze with ids sourced from resources and datasources. Projects can be sourced from different spaces, a single scope can only reference projects and environments from the same space.
22+
resource "octopusdeploy_deployment_freeze" "freeze" {
23+
name = "End of financial year shutdown"
24+
start = "2025-06-30T00:00:00+10:00"
25+
end = "2025-07-02T00:00:00+10:00"
26+
}
27+
28+
resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
29+
deploymentfreeze_id = octopusdeploy_deployment_freeze.freeze.id
30+
project_id = resource.octopusdeploy_project.project1.id
31+
environment_ids = [resource.octopusdeploy_environment.production.id]
32+
}
33+
34+
resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
35+
deploymentfreeze_id = octopusdeploy_deployment_freeze.freeze.id
36+
project_id = data.octopusdeploy_projects.second_project.projects[0].id
37+
environment_ids = [ data.octopusdeploy_environments.default_environment.environments[0].id ]
38+
}

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/OctopusDeploy/terraform-provider-octopusdeploy
33
go 1.21
44

55
require (
6-
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.60.0
6+
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.62.2
77
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4
88
github.com/google/uuid v1.6.0
99
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
@@ -77,6 +77,7 @@ require (
7777
github.com/hashicorp/logutils v1.0.0 // indirect
7878
github.com/hashicorp/terraform-exec v0.21.0 // indirect
7979
github.com/hashicorp/terraform-json v0.22.1 // indirect
80+
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0 // indirect
8081
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
8182
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
8283
github.com/hashicorp/yamux v0.1.1 // indirect

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ github.com/Microsoft/hcsshim v0.12.4 h1:Ev7YUMHAHoWNm+aDSPzc5W9s6E2jyL1szpVDJeZ/
2020
github.com/Microsoft/hcsshim v0.12.4/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ=
2121
github.com/OctopusDeploy/go-octodiff v1.0.0 h1:U+ORg6azniwwYo+O44giOw6TiD5USk8S4VDhOQ0Ven0=
2222
github.com/OctopusDeploy/go-octodiff v1.0.0/go.mod h1:Mze0+EkOWTgTmi8++fyUc6r0aLZT7qD9gX+31t8MmIU=
23-
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.60.0 h1:9j4IQ1UcAuaTytlBzQ7Mmoy/dLtofYfSGNiM22+sLXs=
24-
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.60.0/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
23+
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.62.2 h1:8CexD1Jnf8ng4S6bHilG7s3+iQOraXZY31Dn0SAxjEM=
24+
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.62.2/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
2525
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4 h1:QfbVf0bOIRMp/WHAWsuVDB7KHoWnRsGbvDuOf2ua7k4=
2626
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4/go.mod h1:Oq9KbiRNDBB5jFmrwnrgLX0urIqR/1ptY18TzkqXm7M=
2727
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
@@ -166,6 +166,8 @@ github.com/hashicorp/terraform-plugin-docs v0.13.0 h1:6e+VIWsVGb6jYJewfzq2ok2smP
166166
github.com/hashicorp/terraform-plugin-docs v0.13.0/go.mod h1:W0oCmHAjIlTHBbvtppWHe8fLfZ2BznQbuv8+UD8OucQ=
167167
github.com/hashicorp/terraform-plugin-framework v1.11.0 h1:M7+9zBArexHFXDx/pKTxjE6n/2UCXY6b8FIq9ZYhwfE=
168168
github.com/hashicorp/terraform-plugin-framework v1.11.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
169+
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0 h1:v3DapR8gsp3EM8fKMh6up9cJUFQ2iRaFsYLP8UJnCco=
170+
github.com/hashicorp/terraform-plugin-framework-timetypes v0.5.0/go.mod h1:c3PnGE9pHBDfdEVG9t1S1C9ia5LW+gkFR0CygXlM8ak=
169171
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc=
170172
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg=
171173
github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co=

internal/errors/error.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package errors
22

33
import (
44
"context"
5+
"github.com/hashicorp/terraform-plugin-framework/resource"
56
"log"
67
"net/http"
78

89
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
910
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
10-
"github.com/hashicorp/terraform-plugin-framework/resource"
1111
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1212
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1313
)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package octopusdeploy_framework
2+
3+
import (
4+
"context"
5+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/deploymentfreezes"
6+
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
7+
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
8+
"github.com/hashicorp/terraform-plugin-framework/attr"
9+
"github.com/hashicorp/terraform-plugin-framework/datasource"
10+
"github.com/hashicorp/terraform-plugin-framework/diag"
11+
"github.com/hashicorp/terraform-plugin-framework/types"
12+
"time"
13+
)
14+
15+
const deploymentFreezeDatasourceName = "deployment_freezes"
16+
17+
type deploymentFreezesModel struct {
18+
ID types.String `tfsdk:"id"`
19+
IDs types.List `tfsdk:"ids"`
20+
PartialName types.String `tfsdk:"partial_name"`
21+
ProjectIDs types.List `tfsdk:"project_ids"`
22+
EnvironmentIDs types.List `tfsdk:"environment_ids"`
23+
IncludeComplete types.Bool `tfsdk:"include_complete"`
24+
Status types.String `tfsdk:"status"`
25+
Skip types.Int64 `tfsdk:"skip"`
26+
Take types.Int64 `tfsdk:"take"`
27+
DeploymentFreezes types.List `tfsdk:"deployment_freezes"`
28+
}
29+
30+
type deploymentFreezeDataSource struct {
31+
*Config
32+
}
33+
34+
func (d *deploymentFreezeDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
35+
d.Config = DataSourceConfiguration(req, resp)
36+
}
37+
38+
func NewDeploymentFreezeDataSource() datasource.DataSource {
39+
return &deploymentFreezeDataSource{}
40+
}
41+
42+
func (d *deploymentFreezeDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
43+
resp.TypeName = util.GetTypeName(deploymentFreezeDatasourceName)
44+
}
45+
46+
func (d *deploymentFreezeDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
47+
resp.Schema = schemas.DeploymentFreezeSchema{}.GetDatasourceSchema()
48+
}
49+
50+
func (d *deploymentFreezeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
51+
var data deploymentFreezesModel
52+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
53+
if resp.Diagnostics.HasError() {
54+
return
55+
}
56+
57+
query := deploymentfreezes.DeploymentFreezeQuery{
58+
IDs: util.Ternary(data.IDs.IsNull(), []string{}, util.ExpandStringList(data.IDs)),
59+
PartialName: data.PartialName.ValueString(),
60+
ProjectIds: util.Ternary(data.ProjectIDs.IsNull(), []string{}, util.ExpandStringList(data.ProjectIDs)),
61+
EnvironmentIds: util.Ternary(data.EnvironmentIDs.IsNull(), []string{}, util.ExpandStringList(data.EnvironmentIDs)),
62+
IncludeComplete: data.IncludeComplete.ValueBool(),
63+
Status: data.Status.ValueString(),
64+
Skip: int(data.Skip.ValueInt64()),
65+
Take: int(data.Take.ValueInt64()),
66+
}
67+
68+
util.DatasourceReading(ctx, "deployment freezes", query)
69+
70+
existingFreezes, err := deploymentfreezes.Get(d.Client, query)
71+
if err != nil {
72+
resp.Diagnostics.AddError("unable to load deployment freezes", err.Error())
73+
return
74+
}
75+
76+
flattenedFreezes := []interface{}{}
77+
for _, freeze := range existingFreezes.DeploymentFreezes {
78+
flattenedFreeze, diags := mapFreezeToAttribute(ctx, freeze)
79+
if diags.HasError() {
80+
resp.Diagnostics.Append(diags...)
81+
return
82+
}
83+
flattenedFreezes = append(flattenedFreezes, flattenedFreeze)
84+
}
85+
86+
data.ID = types.StringValue("Deployment Freezes " + time.Now().UTC().String())
87+
data.DeploymentFreezes, _ = types.ListValueFrom(ctx, types.ObjectType{AttrTypes: freezeObjectType()}, flattenedFreezes)
88+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
89+
}
90+
91+
var _ datasource.DataSource = &deploymentFreezeDataSource{}
92+
var _ datasource.DataSourceWithConfigure = &deploymentFreezeDataSource{}
93+
94+
func mapFreezeToAttribute(ctx context.Context, freeze deploymentfreezes.DeploymentFreeze) (attr.Value, diag.Diagnostics) {
95+
projectScopes := make(map[string]attr.Value)
96+
for projectId, environmentScopes := range freeze.ProjectEnvironmentScope {
97+
projectScopes[projectId] = util.FlattenStringList(environmentScopes)
98+
}
99+
100+
scopeType, diags := types.MapValueFrom(ctx, types.ListType{ElemType: types.StringType}, projectScopes)
101+
if diags.HasError() {
102+
return nil, diags
103+
}
104+
105+
return types.ObjectValueMust(freezeObjectType(), map[string]attr.Value{
106+
"id": types.StringValue(freeze.ID),
107+
"name": types.StringValue(freeze.Name),
108+
"start": types.StringValue(freeze.Start.Format(time.RFC3339)),
109+
"end": types.StringValue(freeze.End.Format(time.RFC3339)),
110+
"project_environment_scope": scopeType,
111+
}), diags
112+
}
113+
114+
func freezeObjectType() map[string]attr.Type {
115+
return map[string]attr.Type{
116+
"id": types.StringType,
117+
"name": types.StringType,
118+
"start": types.StringType,
119+
"end": types.StringType,
120+
"project_environment_scope": types.MapType{ElemType: types.ListType{ElemType: types.StringType}},
121+
}
122+
}

octopusdeploy_framework/framework_provider.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func (p *octopusDeployFrameworkProvider) DataSources(ctx context.Context) []func
8686
NewUsersDataSource,
8787
NewServiceAccountOIDCIdentityDataSource,
8888
NewWorkersDataSource,
89+
NewDeploymentFreezeDataSource,
8990
}
9091
}
9192

@@ -126,6 +127,8 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
126127
NewSSHConnectionWorkerResource,
127128
NewScriptModuleResource,
128129
NewUserResource,
130+
NewDeploymentFreezeResource,
131+
NewDeploymentFreezeProjectResource,
129132
NewServiceAccountOIDCIdentity,
130133
}
131134
}

0 commit comments

Comments
 (0)