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

Conversation

@benPearce1
Copy link
Collaborator

@benPearce1 benPearce1 commented Nov 21, 2024

Source

resource "octopusdeploy_deployment_freeze" "freeze" {
  name = "Xmas"
  start = "2024-12-25T00:00:00+10:00"
  end = "2024-12-27T00:00:00+08:00"
}

resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
  deploymentfreeze_id= octopusdeploy_deployment_freeze.freeze.id
  project_id = resource.octopusdeploy_project.project1.id
  environment_ids = [resource.octopusdeploy_environment.dev.id, resource.octopusdeploy_environment.test.id]
}

resource "octopusdeploy_deployment_freeze_project" "project_freeze_2" {
  deploymentfreeze_id= octopusdeploy_deployment_freeze.freeze.id
  project_id = data.octopusdeploy_projects.second_project.projects[0].id
  environment_ids = [ data.octopusdeploy_environments.default_environment.environments[0].id ]
 }

Create

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # octopusdeploy_deployment_freeze.freeze will be created
  + resource "octopusdeploy_deployment_freeze" "freeze" {
      + end   = "2024-12-27T00:00:00+08:00"
      + id    = (known after apply)
      + name  = "Xmas"
      + start = "2024-12-25T00:00:00+10:00"
    }

  # octopusdeploy_deployment_freeze_project.project_freeze will be created
  + resource "octopusdeploy_deployment_freeze_project" "project_freeze" {
      + deploymentfreeze_id = (known after apply)
      + environment_ids     = [
          + "Environments-1561",
          + "Environments-1562",
        ]
      + id                  = (known after apply)
      + project_id          = "Projects-3161"
    }

  # octopusdeploy_deployment_freeze_project.project_freeze_2 will be created
  + resource "octopusdeploy_deployment_freeze_project" "project_freeze_2" {
      + deploymentfreeze_id = (known after apply)
      + environment_ids     = [
          + "Environments-223",
        ]
      + id                  = (known after apply)
      + project_id          = "Projects-2713"
    }

Plan: 3 to add, 0 to change, 0 to destroy.
octopusdeploy_deployment_freeze.freeze: Creating...
octopusdeploy_deployment_freeze.freeze: Creation complete after 0s [id=DeploymentFreezes-262]
octopusdeploy_deployment_freeze_project.project_freeze_2: Creating...
octopusdeploy_deployment_freeze_project.project_freeze: Creating...
octopusdeploy_deployment_freeze_project.project_freeze: Creation complete after 0s [id=DeploymentFreezes-262:Projects-3161]
octopusdeploy_deployment_freeze_project.project_freeze_2: Creation complete after 0s [id=DeploymentFreezes-262:Projects-2713]

image

Update

end = "2024-12-27T00:00:00+10:00"

Terraform will perform the following actions:

  # octopusdeploy_deployment_freeze.freeze will be updated in-place
  ~ resource "octopusdeploy_deployment_freeze" "freeze" {
      ~ end                       = "2024-12-26T16:00:00Z" -> "2024-12-27T00:00:00+10:00"
        id                        = "DeploymentFreezes-113"
        name                      = "Xmas"
      ~ start                     = "2024-12-24T16:00:00Z" -> "2024-12-25T00:00:00+08:00"
        # (1 unchanged attribute hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.
octopusdeploy_deployment_freeze.freeze: Modifying... [id=DeploymentFreezes-113]
octopusdeploy_deployment_freeze.freeze: Modifications complete after 1s [id=DeploymentFreezes-113]

image

Destroy

Terraform will perform the following actions:

  # octopusdeploy_deployment_freeze.freeze will be destroyed
  # (because octopusdeploy_deployment_freeze.freeze is not in configuration)
  - resource "octopusdeploy_deployment_freeze" "freeze" {
      - end                       = "2024-12-27T00:00:00+10:00" -> null
      - id                        = "DeploymentFreezes-113" -> null
      - name                      = "Xmas" -> null
      - project_environment_scope = {
          - "Projects-2713" = [
              - "Environments-223",
            ]
          - "Projects-3084" = [
              - "Environments-1506",
              - "Environments-1507",
            ]
        } -> null
      - start                     = "2024-12-25T00:00:00+08:00" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.
octopusdeploy_deployment_freeze.freeze: Destroying... [id=DeploymentFreezes-113]
octopusdeploy_deployment_freeze.freeze: Destruction complete after 0s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.

Datasource

data "octopusdeploy_deployment_freezes" "all_freezes" {
  skip = 0
  take = 10
  partial_name = "empty"
}

output "all_freezes" {
  value = data.octopusdeploy_deployment_freezes.all_freezes
}

Output:

all_freezes = {
  "deployment_freezes" = tolist([
    {
      "end" = "2024-11-25T04:45:53Z"
      "id" = "DeploymentFreezes-163"
      "name" = "empty via ui"
      "project_environment_scope" = tomap({
        "Projects-2716" = tolist([
          "Environments-1176",
        ])
      })
      "start" = "2024-11-25T04:15:53Z"
    },
    {
      "end" = "2025-11-15T22:42:09+10:00"
      "id" = "DeploymentFreezes-181"
      "name" = "empty"
      "project_environment_scope" = tomap({})
      "start" = "2025-11-05T10:12:09+10:00"
    },
    {
      "end" = "2025-11-15T22:42:09+10:00"
      "id" = "DeploymentFreezes-201"
      "name" = "empty2"
      "project_environment_scope" = tomap({})
      "start" = "2025-11-05T10:12:09+10:00"
    },
  ])
  "environment_ids" = tolist(null) /* of string */
  "id" = "Deployment Freezes 2024-11-28 07:20:05.291351 +0000 UTC"
  "ids" = tolist(null) /* of string */
  "include_complete" = tobool(null)
  "partial_name" = "empty"
  "project_ids" = tolist(null) /* of string */
  "skip" = 0
  "status" = tostring(null)
  "take" = 10
}

}

func DeleteFromStateV2(ctx context.Context, resp *resource.ReadResponse, resource schemas.IResourceModel, resourceDescription string) error {
func DeleteFromStateV2(ctx context.Context, state *tfsdk.State, resource schemas.IResourceModel, resourceDescription string) error {
Copy link
Collaborator Author

@benPearce1 benPearce1 Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes in this file allow this functionality to be used in the delete and read functions
this also accounts for the majority of small changes

Comment on lines 163 to 166
if useSourceForDates {
state.Start = types.StringValue(deploymentFreeze.Start.Format(time.RFC3339))
state.End = types.StringValue(deploymentFreeze.End.Format(time.RFC3339))
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the time contains a timezone the value for the times are returned with a server local timezone, for create and update operations we just store the value provided in the plan, for a refresh (read) operation it will store the value from the api as it may have been changed.

}

func GetDateTimeResourceSchema(description string, isRequired bool) resourceSchema.Attribute {
regex := "^((?:(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?))(?:Z|[\\+-]\\d{2}:\\d{2})?)"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the RFC3339 specification
https://regex101.com/r/qH0sU7/1

Comment on lines -313 to -319
func convertMapStringToMapAttrValue(m map[string]string) map[string]attr.Value {
result := make(map[string]attr.Value, len(m))
for k, v := range m {
result[k] = types.StringValue(v)
}
return result
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved to util.go

@benPearce1 benPearce1 marked this pull request as ready for review November 22, 2024 00:29
Copy link
Contributor

@domenicsim1 domenicsim1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions about the error handling. Did we mean to fall through the error conditions?

Also please add and addition step to the test so we cover update.


updatedFreeze, err = deploymentfreezes.Update(f.Config.Client, updatedFreeze)
if err != nil {
resp.Diagnostics.AddError("error while updating deployment freeze", err.Error())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing return?


updatedFreeze, err := mapFromState(plan)
if err != nil {
resp.Diagnostics.AddError("error while mapping deployment freeze", err.Error())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing return?


err = deploymentfreezes.Delete(f.Config.Client, freeze)
if err != nil {
resp.Diagnostics.AddError("unable to delete deployment freeze", err.Error())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return?

resource.TestCheckResourceAttr(resourceName, "start", start),
resource.TestCheckResourceAttr(resourceName, "end", end)),
Config: testDeploymentFreezeBasic(localName, name, start, end, spaceName, environmentName, projectName, projectGroupName, lifecycleName),
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add one more step so we can also test update.

}

plan.ID = types.StringValue(schemas.BuildTenantProjectID(spaceId, plan.TenantID.ValueString(), plan.ProjectID.ValueString()))
plan.ID = types.StringValue(util.BuildCompositeId(spaceId, plan.TenantID.ValueString(), plan.ProjectID.ValueString()))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to shared function

}

bits := strings.Split(data.ID.ValueString(), ":")
bits := util.SplitCompositeId(data.ID.ValueString())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to shared function

Copy link
Contributor

@domenicsim1 domenicsim1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, left some comments

resource.TestCheckResourceAttr(resourceName, "end", end)),
Config: testDeploymentFreezeBasic(localName, name, start, end, spaceName, []string{environmentName1}, projectName, projectGroupName, lifecycleName),
},
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would appreciate if we run a 2nd step with an updated config so we can test the update function for the resource

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put in an update as a second resource.Test block. I will move it into the same set and make the update do more changes

}

location := stateTime.Location()
newValue := timetypes.NewRFC3339TimeValue(updatedValueUTC.In(location))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stores the time in state using the timezone used in the config

Copy link
Collaborator

@HuyPhanNguyen HuyPhanNguyen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull the branch locally and run test. All look good to me.

@benPearce1 benPearce1 merged commit eede862 into main Dec 4, 2024
22 checks passed
@benPearce1 benPearce1 deleted the bp/deployment-freeze branch December 4, 2024 23:12
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants