Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: deployment freezes #822

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open

feat: deployment freezes #822

wants to merge 29 commits into from

Conversation

benPearce1
Copy link
Collaborator

@benPearce1 benPearce1 commented Nov 21, 2024

Note: for some reason running tfplugindocs resulted in an update to remove some whitespace from most of the docs files.

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
}

@@ -32,20 +32,20 @@ func ProcessApiError(ctx context.Context, d *schema.ResourceData, err error, res
return diag.FromErr(err)
}

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.

@@ -432,3 +433,14 @@ func GetSensitiveResourceSchema(description string, isRequired bool) resourceSch

return s
}

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

@@ -83,7 +82,7 @@ func (t *tenantProjectResource) Read(ctx context.Context, req resource.ReadReque
return
}

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants