diff --git a/docs/data-sources/deployment_freezes.md b/docs/data-sources/deployment_freezes.md
index b23bd14f..fdeff304 100644
--- a/docs/data-sources/deployment_freezes.md
+++ b/docs/data-sources/deployment_freezes.md
@@ -42,6 +42,7 @@ Read-Only:
- `project_environment_scope` (Map of List of String) The project environment scope of the deployment freeze
- `recurring_schedule` (Attributes) (see [below for nested schema](#nestedatt--deployment_freezes--recurring_schedule))
- `start` (String) The start time of the freeze
+- `tenant_project_environment_scope` (Attributes List) The tenant project environment scope of the deployment freeze (see [below for nested schema](#nestedatt--deployment_freezes--tenant_project_environment_scope))
### Nested Schema for `deployment_freezes.recurring_schedule`
@@ -60,3 +61,13 @@ Read-Only:
- `unit` (Number) The unit value for the schedule
+
+### Nested Schema for `deployment_freezes.tenant_project_environment_scope`
+
+Read-Only:
+
+- `environment_id` (String) The environment ID
+- `project_id` (String) The project ID
+- `tenant_id` (String) The tenant ID
+
+
diff --git a/octopusdeploy_framework/datasource_deployment_freeze.go b/octopusdeploy_framework/datasource_deployment_freeze.go
index b3fb8d3d..ab7288f1 100644
--- a/octopusdeploy_framework/datasource_deployment_freeze.go
+++ b/octopusdeploy_framework/datasource_deployment_freeze.go
@@ -14,28 +14,6 @@ import (
const deploymentFreezeDatasourceName = "deployment_freezes"
-type recurringScheduleDatasourceModel struct {
- Type types.String `tfsdk:"type"`
- Unit types.Int64 `tfsdk:"unit"`
- EndType types.String `tfsdk:"end_type"`
- EndOnDate types.String `tfsdk:"end_on_date"`
- EndAfterOccurrences types.Int64 `tfsdk:"end_after_occurrences"`
- MonthlyScheduleType types.String `tfsdk:"monthly_schedule_type"`
- DateOfMonth types.String `tfsdk:"date_of_month"`
- DayNumberOfMonth types.String `tfsdk:"day_number_of_month"`
- DaysOfWeek types.List `tfsdk:"days_of_week"`
- DayOfWeek types.String `tfsdk:"day_of_week"`
-}
-
-type deploymentFreezeDatasourceModel struct {
- ID types.String `tfsdk:"id"`
- Name types.String `tfsdk:"name"`
- Start types.String `tfsdk:"start"`
- End types.String `tfsdk:"end"`
- ProjectEnvironmentScope types.Map `tfsdk:"project_environment_scope"`
- RecurringSchedule *recurringScheduleDatasourceModel `tfsdk:"recurring_schedule"`
-}
-
type deploymentFreezesDatasourceModel struct {
ID types.String `tfsdk:"id"`
IDs types.List `tfsdk:"ids"`
@@ -114,27 +92,55 @@ var _ datasource.DataSource = &deploymentFreezeDataSource{}
var _ datasource.DataSourceWithConfigure = &deploymentFreezeDataSource{}
func mapFreezeToAttribute(ctx context.Context, freeze deploymentfreezes.DeploymentFreeze) (attr.Value, diag.Diagnostics) {
+ var diags diag.Diagnostics
+
projectScopes := make(map[string]attr.Value)
for projectId, environmentScopes := range freeze.ProjectEnvironmentScope {
projectScopes[projectId] = util.FlattenStringList(environmentScopes)
}
- scopeType, diags := types.MapValueFrom(ctx, types.ListType{ElemType: types.StringType}, projectScopes)
- if diags.HasError() {
+ scopeType, scopeDiags := types.MapValueFrom(ctx, types.ListType{ElemType: types.StringType}, projectScopes)
+ if scopeDiags.HasError() {
+ diags.Append(scopeDiags...)
+ return nil, diags
+ }
+
+ tenantScopes := make([]attr.Value, 0)
+ for _, scope := range freeze.TenantProjectEnvironmentScope {
+ tenantScope, tDiags := types.ObjectValue(tenantScopeObjectType(), map[string]attr.Value{
+ "tenant_id": types.StringValue(scope.TenantId),
+ "project_id": types.StringValue(scope.ProjectId),
+ "environment_id": types.StringValue(scope.EnvironmentId),
+ })
+ if tDiags.HasError() {
+ diags.Append(tDiags...)
+ return nil, diags
+ }
+ tenantScopes = append(tenantScopes, tenantScope)
+ }
+
+ tenantScopesList, tsDiags := types.ListValue(
+ types.ObjectType{AttrTypes: tenantScopeObjectType()},
+ tenantScopes,
+ )
+ if tsDiags.HasError() {
+ diags.Append(tsDiags...)
return nil, diags
}
attrs := map[string]attr.Value{
- "id": types.StringValue(freeze.ID),
- "name": types.StringValue(freeze.Name),
- "start": types.StringValue(freeze.Start.Format(time.RFC3339)),
- "end": types.StringValue(freeze.End.Format(time.RFC3339)),
- "project_environment_scope": scopeType,
+ "id": types.StringValue(freeze.ID),
+ "name": types.StringValue(freeze.Name),
+ "start": types.StringValue(freeze.Start.Format(time.RFC3339)),
+ "end": types.StringValue(freeze.End.Format(time.RFC3339)),
+ "project_environment_scope": scopeType,
+ "tenant_project_environment_scope": tenantScopesList,
}
if freeze.RecurringSchedule != nil {
- daysOfWeek, diags := types.ListValueFrom(ctx, types.StringType, freeze.RecurringSchedule.DaysOfWeek)
- if diags.HasError() {
+ daysOfWeek, daysDiags := types.ListValueFrom(ctx, types.StringType, freeze.RecurringSchedule.DaysOfWeek)
+ if daysDiags.HasError() {
+ diags.Append(daysDiags...)
return nil, diags
}
@@ -181,8 +187,9 @@ func mapFreezeToAttribute(ctx context.Context, freeze deploymentfreezes.Deployme
"day_of_week": dayOfWeek,
}
- recurringSchedule, diags := types.ObjectValue(freezeRecurringScheduleObjectType(), scheduleAttrs)
- if diags.HasError() {
+ recurringSchedule, rsDiags := types.ObjectValue(freezeRecurringScheduleObjectType(), scheduleAttrs)
+ if rsDiags.HasError() {
+ diags.Append(rsDiags...)
return nil, diags
}
@@ -209,13 +216,22 @@ func freezeRecurringScheduleObjectType() map[string]attr.Type {
}
}
+func tenantScopeObjectType() map[string]attr.Type {
+ return map[string]attr.Type{
+ "tenant_id": types.StringType,
+ "project_id": types.StringType,
+ "environment_id": types.StringType,
+ }
+}
+
func freezeObjectType() map[string]attr.Type {
return map[string]attr.Type{
- "id": types.StringType,
- "name": types.StringType,
- "start": types.StringType,
- "end": types.StringType,
- "project_environment_scope": types.MapType{ElemType: types.ListType{ElemType: types.StringType}},
- "recurring_schedule": types.ObjectType{AttrTypes: freezeRecurringScheduleObjectType()},
+ "id": types.StringType,
+ "name": types.StringType,
+ "start": types.StringType,
+ "end": types.StringType,
+ "project_environment_scope": types.MapType{ElemType: types.ListType{ElemType: types.StringType}},
+ "tenant_project_environment_scope": types.ListType{ElemType: types.ObjectType{AttrTypes: tenantScopeObjectType()}},
+ "recurring_schedule": types.ObjectType{AttrTypes: freezeRecurringScheduleObjectType()},
}
}
diff --git a/octopusdeploy_framework/datasource_deployment_freeze_test.go b/octopusdeploy_framework/datasource_deployment_freeze_test.go
index b5ad302b..55c1b359 100644
--- a/octopusdeploy_framework/datasource_deployment_freeze_test.go
+++ b/octopusdeploy_framework/datasource_deployment_freeze_test.go
@@ -11,9 +11,11 @@ import (
func TestAccDataSourceDeploymentFreezes(t *testing.T) {
spaceName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
freezeName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
- resourceName := "data.octopusdeploy_deployment_freezes.test_freeze"
+ tenantName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ projectName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ environmentName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ dataSourceName := "data.octopusdeploy_deployment_freezes.test_freeze"
- // Use future dates for the freeze period, ensuring UTC timezone
startTime := time.Now().AddDate(1, 0, 0).UTC()
endTime := startTime.Add(24 * time.Hour)
@@ -22,69 +24,137 @@ func TestAccDataSourceDeploymentFreezes(t *testing.T) {
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
- Config: testAccDataSourceDeploymentFreezesConfig(spaceName, freezeName, startTime, endTime),
+ Config: testAccDataSourceDeploymentFreezesConfig(spaceName, freezeName, startTime, endTime, false, projectName, environmentName, tenantName),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttrSet(resourceName, "id"),
- resource.TestCheckResourceAttr(resourceName, "partial_name", freezeName),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.#", "1"),
- resource.TestCheckResourceAttrSet(resourceName, "deployment_freezes.0.id"),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.name", freezeName),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.start", startTime.Format(time.RFC3339)),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.end", endTime.Format(time.RFC3339)),
- resource.TestCheckResourceAttrSet(resourceName, "deployment_freezes.0.project_environment_scope.%"),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.type", "DaysPerWeek"),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.unit", "24"),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.end_type", "AfterOccurrences"),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.end_after_occurrences", "5"),
- resource.TestCheckResourceAttr(resourceName, "deployment_freezes.0.recurring_schedule.days_of_week.#", "3"),
- testAccCheckOutputExists("octopus_space_id"),
- testAccCheckOutputExists("octopus_freeze_id"),
+ resource.TestCheckResourceAttrSet(dataSourceName, "id"),
+ resource.TestCheckResourceAttr(dataSourceName, "partial_name", freezeName),
+ resource.TestCheckResourceAttr(dataSourceName, "deployment_freezes.#", "1"),
+ resource.TestCheckResourceAttr(dataSourceName, "deployment_freezes.0.name", freezeName),
+ resource.TestCheckResourceAttr(dataSourceName, "deployment_freezes.0.tenant_project_environment_scope.#", "0"),
+ ),
+ },
+ {
+ Config: testAccDataSourceDeploymentFreezesConfig(spaceName, freezeName, startTime, endTime, true, projectName, environmentName, tenantName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrSet(dataSourceName, "id"),
+ resource.TestCheckResourceAttr(dataSourceName, "deployment_freezes.0.tenant_project_environment_scope.#", "1"),
+ resource.TestCheckResourceAttrSet(dataSourceName, "deployment_freezes.0.tenant_project_environment_scope.0.tenant_id"),
+ resource.TestCheckResourceAttrSet(dataSourceName, "deployment_freezes.0.tenant_project_environment_scope.0.project_id"),
+ resource.TestCheckResourceAttrSet(dataSourceName, "deployment_freezes.0.tenant_project_environment_scope.0.environment_id"),
),
},
},
})
}
-func testAccDataSourceDeploymentFreezesConfig(spaceName, freezeName string, startTime, endTime time.Time) string {
- return fmt.Sprintf(`
+func testAccDataSourceDeploymentFreezesConfig(spaceName, freezeName string, startTime, endTime time.Time, includeTenant bool, projectName, environmentName, tenantName string) string {
+ baseConfig := fmt.Sprintf(`
resource "octopusdeploy_space" "test_space" {
- name = "%s"
- is_default = false
- is_task_queue_stopped = false
- description = "Test space for deployment freeze datasource"
- space_managers_teams = ["teams-administrators"]
+ name = "%s"
+ is_default = false
+ is_task_queue_stopped = false
+ description = "Test space for deployment freeze datasource"
+ space_managers_teams = ["teams-administrators"]
+}
+
+resource "octopusdeploy_environment" "test_environment" {
+ name = "%s"
+ description = "Test environment"
+ space_id = octopusdeploy_space.test_space.id
+}
+
+resource "octopusdeploy_project_group" "test_project_group" {
+ name = "Test Project Group"
+ description = "Test project group for deployment freeze datasource"
+ space_id = octopusdeploy_space.test_space.id
+}
+
+resource "octopusdeploy_lifecycle" "test_lifecycle" {
+ name = "Test Lifecycle"
+ space_id = octopusdeploy_space.test_space.id
+}
+
+resource "octopusdeploy_project" "test_project" {
+ name = "%s"
+ lifecycle_id = octopusdeploy_lifecycle.test_lifecycle.id
+ project_group_id = octopusdeploy_project_group.test_project_group.id
+ space_id = octopusdeploy_space.test_space.id
}
resource "octopusdeploy_deployment_freeze" "test_freeze" {
- name = "%s"
- start = "%s"
- end = "%s"
-
- recurring_schedule = {
- type = "DaysPerWeek"
- unit = 24
- end_type = "AfterOccurrences"
- end_after_occurrences = 5
- days_of_week = ["Monday", "Wednesday", "Friday"]
- }
+ name = "%s"
+ start = "%s"
+ end = "%s"
+
+ recurring_schedule = {
+ type = "DaysPerWeek"
+ unit = 24
+ end_type = "AfterOccurrences"
+ end_after_occurrences = 5
+ days_of_week = ["Monday", "Wednesday", "Friday"]
+ }
+
+ depends_on = [octopusdeploy_space.test_space]
+}
+`, spaceName, environmentName, projectName, freezeName, startTime.Format(time.RFC3339), endTime.Format(time.RFC3339))
+
+ if includeTenant {
+ tenantConfig := fmt.Sprintf(`
+resource "octopusdeploy_tenant" "test_tenant" {
+ name = "%s"
+ space_id = octopusdeploy_space.test_space.id
+}
+
+resource "octopusdeploy_tenant_project" "test_tenant_project" {
+ tenant_id = octopusdeploy_tenant.test_tenant.id
+ project_id = octopusdeploy_project.test_project.id
+ environment_ids = [octopusdeploy_environment.test_environment.id]
+ space_id = octopusdeploy_space.test_space.id
+}
+
+resource "octopusdeploy_deployment_freeze_tenant" "test_tenant_scope" {
+ deploymentfreeze_id = octopusdeploy_deployment_freeze.test_freeze.id
+ tenant_id = octopusdeploy_tenant.test_tenant.id
+ project_id = octopusdeploy_project.test_project.id
+ environment_id = octopusdeploy_environment.test_environment.id
- depends_on = [octopusdeploy_space.test_space]
+ depends_on = [
+ octopusdeploy_tenant_project.test_tenant_project
+ ]
}
+`, tenantName)
+ baseConfig = baseConfig + tenantConfig
+ }
+ datasourceConfig := `
data "octopusdeploy_deployment_freezes" "test_freeze" {
- ids = null
- partial_name = "%s"
- skip = 0
- take = 1
- depends_on = [octopusdeploy_deployment_freeze.test_freeze]
+ ids = null
+ partial_name = "%s"
+ skip = 0
+ take = 1
+ depends_on = [`
+
+ if includeTenant {
+ datasourceConfig += `
+ octopusdeploy_deployment_freeze.test_freeze,
+ octopusdeploy_deployment_freeze_tenant.test_tenant_scope
+ `
+ } else {
+ datasourceConfig += `
+ octopusdeploy_deployment_freeze.test_freeze
+ `
+ }
+
+ datasourceConfig += `]
}
output "octopus_space_id" {
- value = octopusdeploy_space.test_space.id
+ value = octopusdeploy_space.test_space.id
}
output "octopus_freeze_id" {
- value = data.octopusdeploy_deployment_freezes.test_freeze.deployment_freezes[0].id
+ value = data.octopusdeploy_deployment_freezes.test_freeze.deployment_freezes[0].id
}
-`, spaceName, freezeName, startTime.Format(time.RFC3339), endTime.Format(time.RFC3339), freezeName)
+`
+ return baseConfig + fmt.Sprintf(datasourceConfig, freezeName)
}
diff --git a/octopusdeploy_framework/schemas/deployment_freeze.go b/octopusdeploy_framework/schemas/deployment_freeze.go
index 3d986d7a..810c81d6 100644
--- a/octopusdeploy_framework/schemas/deployment_freeze.go
+++ b/octopusdeploy_framework/schemas/deployment_freeze.go
@@ -61,6 +61,7 @@ func (d DeploymentFreezeSchema) GetResourceSchema() resourceSchema.Schema {
},
}
}
+
func (d DeploymentFreezeSchema) GetDatasourceSchema() datasourceSchema.Schema {
return datasourceSchema.Schema{
Description: "Provides information about deployment freezes",
@@ -92,23 +93,39 @@ func (d DeploymentFreezeSchema) GetDatasourceSchema() datasourceSchema.Schema {
"name": GetReadonlyNameDatasourceSchema(),
"start": datasourceSchema.StringAttribute{
Description: "The start time of the freeze",
- Optional: false,
Computed: true,
},
"end": datasourceSchema.StringAttribute{
Description: "The end time of the freeze",
- Optional: false,
Computed: true,
},
"project_environment_scope": datasourceSchema.MapAttribute{
ElementType: types.ListType{ElemType: types.StringType},
Description: "The project environment scope of the deployment freeze",
- Optional: false,
Computed: true,
},
+ "tenant_project_environment_scope": datasourceSchema.ListNestedAttribute{
+ Description: "The tenant project environment scope of the deployment freeze",
+ Computed: true,
+ NestedObject: datasourceSchema.NestedAttributeObject{
+ Attributes: map[string]datasourceSchema.Attribute{
+ "tenant_id": datasourceSchema.StringAttribute{
+ Description: "The tenant ID",
+ Computed: true,
+ },
+ "project_id": datasourceSchema.StringAttribute{
+ Description: "The project ID",
+ Computed: true,
+ },
+ "environment_id": datasourceSchema.StringAttribute{
+ Description: "The environment ID",
+ Computed: true,
+ },
+ },
+ },
+ },
"recurring_schedule": datasourceSchema.SingleNestedAttribute{
Computed: true,
- Optional: false,
Attributes: map[string]datasourceSchema.Attribute{
"type": datasourceSchema.StringAttribute{
Description: "Type of recurring schedule (OnceDaily, DaysPerWeek, DaysPerMonth, Annually)",
@@ -155,7 +172,6 @@ func (d DeploymentFreezeSchema) GetDatasourceSchema() datasourceSchema.Schema {
},
},
},
- Optional: false,
Computed: true,
},
},