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

Commit 3d8facb

Browse files
committed
feat(tf-actions): Add destroy and plan tf action support
1 parent 5659b72 commit 3d8facb

5 files changed

+202
-22
lines changed

octopusdeploy/schema_action_apply_terraform_template.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ func addTerraformTemplateAdvancedOptionsSchema(element *schema.Resource) {
4242
}
4343
}
4444

45+
func addTerraformTemplatePlanSchema(element *schema.Resource) {
46+
element.Schema["is_plan"] = &schema.Schema{
47+
Optional: true,
48+
Type: schema.TypeBool,
49+
Default: false,
50+
Description: "Determines whether the action only generates a terraform plan",
51+
}
52+
}
53+
4554
func addTerraformTemplateAwsAccountSchema(element *schema.Resource) {
4655
element.Schema["aws_account"] = &schema.Schema{
4756
Elem: &schema.Resource{
@@ -166,10 +175,7 @@ func flattenTerraformTemplate(properties map[string]octopusdeploy.PropertyValue)
166175
return []interface{}{flattenedMap}
167176
}
168177

169-
func expandApplyTerraformTemplateAction(flattenedAction map[string]interface{}) *octopusdeploy.DeploymentAction {
170-
action := expandAction(flattenedAction)
171-
action.ActionType = "Octopus.TerraformApply"
172-
178+
func expandTerraformTemplateAction(flattenedAction map[string]interface{}, action *octopusdeploy.DeploymentAction) {
173179
if v, ok := flattenedAction["template"]; ok {
174180
template := v.(*schema.Set).List()[0].(map[string]interface{})
175181

@@ -275,7 +281,15 @@ func expandApplyTerraformTemplateAction(flattenedAction map[string]interface{})
275281
action.Properties["Octopus.Action.AzureAccount.Variable"] = octopusdeploy.NewPropertyValue(v.(string), false)
276282
}
277283
}
278-
284+
}
285+
func expandApplyTerraformTemplateAction(flattenedAction map[string]interface{}) *octopusdeploy.DeploymentAction {
286+
action := expandAction(flattenedAction)
287+
if isPlan, ok := flattenedAction["is_plan"].(bool); ok && isPlan {
288+
action.ActionType = "Octopus.TerraformPlan"
289+
} else {
290+
action.ActionType = "Octopus.TerraformApply"
291+
}
292+
expandTerraformTemplateAction(flattenedAction, action)
279293
return action
280294
}
281295

@@ -369,7 +383,7 @@ func flattenTerraformTemplateAzureAccount(properties map[string]octopusdeploy.Pr
369383
return []interface{}{flattenedMap}
370384
}
371385

372-
func flattenApplyTerraformTemplateAction(action *octopusdeploy.DeploymentAction) map[string]interface{} {
386+
func flattenTerraformTemplateAction(action *octopusdeploy.DeploymentAction) map[string]interface{} {
373387
flattenedAction := flattenAction(action)
374388

375389
for k, v := range action.Properties {
@@ -401,9 +415,10 @@ func flattenApplyTerraformTemplateAction(action *octopusdeploy.DeploymentAction)
401415
return flattenedAction
402416
}
403417

404-
func getApplyTerraformTemplateActionSchema() *schema.Schema {
418+
func getTerraformTemplateActionSchema() *schema.Schema {
405419
actionSchema, element := getActionSchema()
406420
addExecutionLocationSchema(element)
421+
addTerraformTemplatePlanSchema(element)
407422
addTerraformTemplateAdvancedOptionsSchema(element)
408423
addTerraformTemplateAwsAccountSchema(element)
409424
addTerraformTemplateAzureAccountSchema(element)

octopusdeploy/schema_action_apply_terraform_template_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func TestAccOctopusDeployApplyTerraformAction(t *testing.T) {
1818
name := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
1919
pluginCacheDirectory := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
2020
runOnServer := acctest.RandIntRange(0, 2) == 0
21+
isPlan := acctest.RandIntRange(0, 2) == 0
2122
workspace := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
2223

2324
scriptSource := "Inline"
@@ -45,19 +46,20 @@ func TestAccOctopusDeployApplyTerraformAction(t *testing.T) {
4546
Steps: []resource.TestStep{
4647
{
4748
Check: resource.ComposeTestCheckFunc(
48-
testAccCheckApplyTerraformAction(name, runOnServer, scriptSource, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace, source, parameters),
49+
testAccCheckApplyTerraformAction(name, runOnServer, isPlan, scriptSource, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace, source, parameters),
4950
),
50-
Config: testAccApplyTerraformAction(name, runOnServer, scriptSource, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace, source, parameters),
51+
Config: testAccApplyTerraformAction(name, runOnServer, isPlan, scriptSource, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace, source, parameters),
5152
},
5253
},
5354
})
5455
}
5556

56-
func testAccApplyTerraformAction(name string, runOnServer bool, templateSource string, allowPluginDownloads bool, applyParameters string, initParameters string, pluginCacheDirectory string, workspace string, template string, templateParameters string) string {
57+
func testAccApplyTerraformAction(name string, runOnServer bool, isPlan bool, templateSource string, allowPluginDownloads bool, applyParameters string, initParameters string, pluginCacheDirectory string, workspace string, template string, templateParameters string) string {
5758
return testAccBuildTestAction(fmt.Sprintf(`
5859
apply_terraform_template_action {
5960
name = "%s"
6061
run_on_server = %v
62+
is_plan = %v
6163
6264
template {
6365
additional_variable_files = "additional-variable-files"
@@ -95,10 +97,10 @@ func testAccApplyTerraformAction(name string, runOnServer bool, templateSource s
9597
package_id = "MyPackage"
9698
feed_id = "feeds-builtin"
9799
}
98-
}`, name, runOnServer, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace))
100+
}`, name, runOnServer, isPlan, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace))
99101
}
100102

101-
func testAccCheckApplyTerraformAction(name string, runOnServer bool, scriptSource string, allowPluginDownloads bool, applyParameters string, initParameters string, pluginCacheDirectory string, workspace string, source string, parameters string) resource.TestCheckFunc {
103+
func testAccCheckApplyTerraformAction(name string, runOnServer bool, isPlan bool, scriptSource string, allowPluginDownloads bool, applyParameters string, initParameters string, pluginCacheDirectory string, workspace string, source string, parameters string) resource.TestCheckFunc {
102104
return func(s *terraform.State) error {
103105
client := testAccProvider.Meta().(*octopusdeploy.Client)
104106

@@ -109,7 +111,11 @@ func testAccCheckApplyTerraformAction(name string, runOnServer bool, scriptSourc
109111

110112
action := process.Steps[0].Actions[0]
111113

112-
if action.ActionType != "Octopus.TerraformApply" {
114+
if !isPlan && action.ActionType != "Octopus.TerraformApply" {
115+
return fmt.Errorf("Action type is incorrect: %s", action.ActionType)
116+
}
117+
118+
if isPlan && action.ActionType != "Octopus.TerraformPlan" {
113119
return fmt.Errorf("Action type is incorrect: %s", action.ActionType)
114120
}
115121

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package octopusdeploy
2+
3+
import (
4+
"github.com/OctopusDeploy/go-octopusdeploy/octopusdeploy"
5+
)
6+
7+
func expandDestroyTerraformTemplateAction(flattenedAction map[string]interface{}) *octopusdeploy.DeploymentAction {
8+
action := expandAction(flattenedAction)
9+
if isPlan, ok := flattenedAction["is_plan"].(bool); ok && isPlan {
10+
action.ActionType = "Octopus.TerraformPlanDestroy"
11+
} else {
12+
action.ActionType = "Octopus.TerraformDestroy"
13+
}
14+
expandTerraformTemplateAction(flattenedAction, action)
15+
16+
return action
17+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package octopusdeploy
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"testing"
7+
8+
"github.com/OctopusDeploy/go-octopusdeploy/octopusdeploy"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
12+
)
13+
14+
func TestAccOctopusDeployDestroyTerraformAction(t *testing.T) {
15+
allowPluginDownloads := acctest.RandIntRange(0, 2) == 0
16+
applyParameters := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
17+
initParameters := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
18+
name := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
19+
pluginCacheDirectory := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
20+
runOnServer := acctest.RandIntRange(0, 2) == 0
21+
isPlan := acctest.RandIntRange(0, 2) == 0
22+
workspace := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
23+
24+
scriptSource := "Inline"
25+
if acctest.RandIntRange(0, 2) == 0 {
26+
scriptSource = "Package"
27+
}
28+
29+
parameters := ""
30+
source := ""
31+
if scriptSource == "Inline" {
32+
variableName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
33+
variableValue := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
34+
source = fmt.Sprintf(`variable \"%s\" { type = string }`, variableName)
35+
parameters = fmt.Sprintf(`{\"%s\":\"%s\"}`, variableName, variableValue)
36+
}
37+
38+
resource.Test(t, resource.TestCase{
39+
CheckDestroy: resource.ComposeTestCheckFunc(
40+
testAccProjectCheckDestroy,
41+
testAccProjectGroupCheckDestroy,
42+
testAccLifecycleCheckDestroy,
43+
),
44+
PreCheck: func() { testAccPreCheck(t) },
45+
Providers: testAccProviders,
46+
Steps: []resource.TestStep{
47+
{
48+
Check: resource.ComposeTestCheckFunc(
49+
testAccCheckDestroyTerraformAction(name, runOnServer, isPlan, scriptSource, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace, source, parameters),
50+
),
51+
Config: testAccDestroyTerraformAction(name, runOnServer, isPlan, scriptSource, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace, source, parameters),
52+
},
53+
},
54+
})
55+
}
56+
57+
func testAccDestroyTerraformAction(name string, runOnServer bool, isPlan bool, templateSource string, allowPluginDownloads bool, applyParameters string, initParameters string, pluginCacheDirectory string, workspace string, template string, templateParameters string) string {
58+
return testAccBuildTestAction(fmt.Sprintf(`
59+
destroy_terraform_template_action {
60+
name = "%s"
61+
run_on_server = %v
62+
is_plan = %v
63+
64+
template {
65+
additional_variable_files = "additional-variable-files"
66+
directory = "template-directory"
67+
run_automatic_file_substitution = false
68+
target_files = "target-files"
69+
}
70+
71+
advanced_options {
72+
allow_additional_plugin_downloads = %v
73+
apply_parameters = "%s"
74+
init_parameters = "%s"
75+
plugin_cache_directory = "%s"
76+
workspace = "%s"
77+
}
78+
79+
aws_account {
80+
region = "us-east-1"
81+
variable = "foo"
82+
use_instance_role = true
83+
84+
role {
85+
arn = "arn"
86+
external_id = "external-id"
87+
role_session_name = "role-session-name"
88+
session_duration = 1800
89+
}
90+
}
91+
92+
azure_account {
93+
variable = "qwe"
94+
}
95+
96+
primary_package {
97+
package_id = "MyPackage"
98+
feed_id = "feeds-builtin"
99+
}
100+
}`, name, runOnServer, isPlan, allowPluginDownloads, applyParameters, initParameters, pluginCacheDirectory, workspace))
101+
}
102+
103+
func testAccCheckDestroyTerraformAction(name string, runOnServer bool, isPlan bool, scriptSource string, allowPluginDownloads bool, applyParameters string, initParameters string, pluginCacheDirectory string, workspace string, source string, parameters string) resource.TestCheckFunc {
104+
return func(s *terraform.State) error {
105+
client := testAccProvider.Meta().(*octopusdeploy.Client)
106+
107+
process, err := getDeploymentProcess(s, client)
108+
if err != nil {
109+
return err
110+
}
111+
112+
action := process.Steps[0].Actions[0]
113+
114+
if !isPlan && action.ActionType != "Octopus.TerraformDestroy" {
115+
return fmt.Errorf("Action type is incorrect: %s", action.ActionType)
116+
}
117+
118+
if isPlan && action.ActionType != "Octopus.TerraformPlanDestroy" {
119+
return fmt.Errorf("Action type is incorrect: %s", action.ActionType)
120+
}
121+
122+
if action.Properties["Octopus.Action.Terraform.AdditionalInitParams"].Value != initParameters {
123+
return fmt.Errorf("AdditionalInitParams: %s", action.Properties["Octopus.Action.Terraform.AdditionalInitParams"].Value)
124+
}
125+
126+
if v, _ := strconv.ParseBool(action.Properties["Octopus.Action.Terraform.AllowPluginDownloads"].Value); v != allowPluginDownloads {
127+
return fmt.Errorf("AllowPluginDownloads: %s", action.Properties["Octopus.Action.Terraform.AllowPluginDownloads"].Value)
128+
}
129+
130+
return nil
131+
}
132+
}

octopusdeploy/schema_deployment_step.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ func expandDeploymentStep(flattenedStep map[string]interface{}) *octopusdeploy.D
7676
}
7777
}
7878

79+
if v, ok := flattenedStep["destroy_terraform_template_action"]; ok {
80+
for _, tfAction := range v.([]interface{}) {
81+
action := expandDestroyTerraformTemplateAction(tfAction.(map[string]interface{}))
82+
step.Actions = append(step.Actions, *action)
83+
}
84+
}
85+
7986
if v, ok := flattenedStep["run_script_action"]; ok {
8087
for _, tfAction := range v.([]interface{}) {
8188
action := expandRunScriptAction(tfAction.(map[string]interface{}))
@@ -138,8 +145,10 @@ func flattenDeploymentSteps(deploymentSteps []octopusdeploy.DeploymentStep) []ma
138145
flattenedDeploymentSteps[key]["run_script_action"] = []interface{}{flattenRunScriptAction(&deploymentStep.Actions[i])}
139146
case "Octopus.TentaclePackage":
140147
flattenedDeploymentSteps[key]["deploy_package_action"] = []interface{}{flattenDeployPackageAction(&deploymentStep.Actions[i])}
141-
case "Octopus.TerraformApply":
142-
flattenedDeploymentSteps[key]["apply_terraform_template_action"] = []interface{}{flattenApplyTerraformTemplateAction(&deploymentStep.Actions[i])}
148+
case "Octopus.TerraformApply", "Octopus.TerraformPlan":
149+
flattenedDeploymentSteps[key]["apply_terraform_template_action"] = []interface{}{flattenTerraformTemplateAction(&deploymentStep.Actions[i])}
150+
case "Octopus.TerraformDestroy", "Octopus.TerraformPlanDestroy":
151+
flattenedDeploymentSteps[key]["destroy_terraform_template_action"] = []interface{}{flattenTerraformTemplateAction(&deploymentStep.Actions[i])}
143152
case "Octopus.WindowsService":
144153
flattenedDeploymentSteps[key]["deploy_windows_service_action"] = []interface{}{flattenDeployWindowsServiceAction(&deploymentStep.Actions[i])}
145154
default:
@@ -156,7 +165,7 @@ func getDeploymentStepSchema() *schema.Schema {
156165
Elem: &schema.Resource{
157166
Schema: map[string]*schema.Schema{
158167
"action": getDeploymentActionSchema(),
159-
"apply_terraform_template_action": getApplyTerraformTemplateActionSchema(),
168+
"apply_terraform_template_action": getTerraformTemplateActionSchema(),
160169
"condition": {
161170
Default: "Success",
162171
Description: "When to run the step, one of 'Success', 'Failure', 'Always' or 'Variable'",
@@ -175,12 +184,13 @@ func getDeploymentStepSchema() *schema.Schema {
175184
Optional: true,
176185
Type: schema.TypeString,
177186
},
178-
"deploy_kubernetes_secret_action": getDeployKubernetesSecretActionSchema(),
179-
"deploy_package_action": getDeployPackageActionSchema(),
180-
"deploy_windows_service_action": getDeployWindowsServiceActionSchema(),
181-
"id": getIDSchema(),
182-
"manual_intervention_action": getManualInterventionActionSchema(),
183-
"name": getNameSchema(true),
187+
"deploy_kubernetes_secret_action": getDeployKubernetesSecretActionSchema(),
188+
"deploy_package_action": getDeployPackageActionSchema(),
189+
"deploy_windows_service_action": getDeployWindowsServiceActionSchema(),
190+
"destroy_terraform_template_action": getTerraformTemplateActionSchema(),
191+
"id": getIDSchema(),
192+
"manual_intervention_action": getManualInterventionActionSchema(),
193+
"name": getNameSchema(true),
184194
"package_requirement": {
185195
Default: "LetOctopusDecide",
186196
Description: "Whether to run this step before or after package acquisition (if possible)",

0 commit comments

Comments
 (0)