diff --git a/integration_test.go b/integration_test.go index 93f829da5..0456c0caf 100644 --- a/integration_test.go +++ b/integration_test.go @@ -36,6 +36,7 @@ package main import ( "fmt" + "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/deployments" "os" "path/filepath" "sort" @@ -3410,3 +3411,64 @@ func TestVariableResource(t *testing.T) { return nil }) } + +// TestTerraformApplyStepWithWorkerPool verifies that a terraform apply step with a custom worker pool is deployed successfully +// See https://github.com/OctopusDeployLabs/terraform-provider-octopusdeploy/issues/601 +func TestTerraformApplyStepWithWorkerPool(t *testing.T) { + testFramework := test.OctopusContainerTest{} + testFramework.ArrangeTest(t, func(t *testing.T, container *test.OctopusContainer, spaceClient *client.Client) error { + // Act + newSpaceId, err := testFramework.Act(t, container, "./terraform", "50-applyterraformtemplateaction", []string{}) + + if err != nil { + return err + } + + // Assert + client, err := octoclient.CreateClient(container.URI, newSpaceId, test.ApiKey) + query := projects.ProjectsQuery{ + PartialName: "Test", + Skip: 0, + Take: 1, + } + + resources, err := projects.Get(client, newSpaceId, query) + if err != nil { + return err + } + + if len(resources.Items) == 0 { + t.Fatalf("Space must have a project called \"Test\"") + } + resource := resources.Items[0] + + // Get worker pool + wpQuery := workerpools.WorkerPoolsQuery{ + PartialName: "Docker", + Skip: 0, + Take: 1, + } + + workerpools, err := workerpools.Get(client, newSpaceId, wpQuery) + if err != nil { + return err + } + + if len(workerpools.Items) == 0 { + t.Fatalf("Space must have a worker pool called \"Docker\"") + } + + // Get deployment process + process, err := deployments.GetDeploymentProcessByID(client, "", resource.DeploymentProcessID) + if err != nil { + return err + } + + // Worker pool must be assigned + if process.Steps[0].Actions[0].WorkerPool != workerpools.Items[0].GetID() { + t.Fatalf("Action must use the worker pool \"Docker\"") + } + + return nil + }) +} diff --git a/octopusdeploy/schema_action_apply_terraform_template.go b/octopusdeploy/schema_action_apply_terraform_template.go index 41c914d6d..55bdd1a4e 100644 --- a/octopusdeploy/schema_action_apply_terraform_template.go +++ b/octopusdeploy/schema_action_apply_terraform_template.go @@ -524,6 +524,14 @@ func flattenApplyTerraformTemplateAction(action *deployments.DeploymentAction) m } } + if len(action.WorkerPool) > 0 { + flattenedAction["worker_pool_id"] = action.WorkerPool + } + + if len(action.WorkerPoolVariable) > 0 { + flattenedAction["worker_pool_variable"] = action.WorkerPoolVariable + } + flattenedAction["advanced_options"] = flattenTerraformTemplateAdvancedOptions(action.Properties) return flattenedAction @@ -539,6 +547,8 @@ func getApplyTerraformTemplateActionSchema() *schema.Schema { addTerraformTemplateParametersSchema(element) addTerraformTemplateSchema(element) addTerraformInlineTemplateSchema(element) + addWorkerPoolSchema(element) + addWorkerPoolVariableSchema(element) addPrimaryPackageSchema(element, false) return actionSchema diff --git a/terraform/50-applyterraformtemplateaction/config.tf b/terraform/50-applyterraformtemplateaction/config.tf new file mode 100644 index 000000000..8a9eaf8a9 --- /dev/null +++ b/terraform/50-applyterraformtemplateaction/config.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + octopusdeploy = { source = "OctopusDeployLabs/octopusdeploy", version = "0.11.3" } + // Use the option below when debugging + // octopusdeploy = { source = "octopus.com/com/octopusdeploy" } + } +} diff --git a/terraform/50-applyterraformtemplateaction/project.tf b/terraform/50-applyterraformtemplateaction/project.tf new file mode 100644 index 000000000..afdf08a17 --- /dev/null +++ b/terraform/50-applyterraformtemplateaction/project.tf @@ -0,0 +1,101 @@ +data "octopusdeploy_lifecycles" "lifecycle_default_lifecycle" { + ids = null + partial_name = "Default Lifecycle" + skip = 0 + take = 1 +} + +data "octopusdeploy_feeds" "feed_octopus_server__built_in_" { + feed_type = "BuiltIn" + ids = null + partial_name = "" + skip = 0 + take = 1 + lifecycle { + postcondition { + error_message = "Failed to resolve a feed called \"BuiltIn\". This resource must exist in the space before this Terraform configuration is applied." + condition = length(self.feeds) != 0 + } + } +} + +resource "octopusdeploy_project" "deploy_frontend_project" { + auto_create_release = false + default_guided_failure_mode = "EnvironmentDefault" + default_to_skip_if_already_installed = false + description = "Test project" + discrete_channel_release = false + is_disabled = false + is_discrete_channel_release = false + is_version_controlled = false + lifecycle_id = data.octopusdeploy_lifecycles.lifecycle_default_lifecycle.lifecycles[0].id + name = "Test" + project_group_id = octopusdeploy_project_group.project_group_test.id + tenanted_deployment_participation = "Untenanted" + space_id = var.octopus_space_id + included_library_variable_sets = [] + versioning_strategy { + template = "#{Octopus.Version.LastMajor}.#{Octopus.Version.LastMinor}.#{Octopus.Version.LastPatch}.#{Octopus.Version.NextRevision}" + } + + connectivity_policy { + allow_deployments_to_no_targets = false + exclude_unhealthy_targets = false + skip_machine_behavior = "SkipUnavailableMachines" + } +} + +resource "octopusdeploy_deployment_process" "deployment_process_terraform_apply" { + project_id = "${octopusdeploy_project.deploy_frontend_project.id}" + + step { + condition = "Success" + name = "Apply a Terraform template" + package_requirement = "LetOctopusDecide" + start_trigger = "StartAfterPrevious" + + apply_terraform_template_action { + name = "Terraform Apply" + can_be_used_for_project_versioning = true + channels = [] + condition = "Success" + environments = [] + advanced_options { + allow_additional_plugin_downloads = true + apply_parameters = "" + init_parameters = "" + plugin_cache_directory = "" + workspace = "" + } + is_disabled = false + is_required = false + + inline_template = "variable \"images\" {\n type = \"map\"\n\n default = {\n us-east-1 = \"image-1234\"\n us-west-2 = \"image-4567\"\n }\n}\n\nvariable \"test2\" {\n type = \"map\"\n default = {\n val1 = [\"hi\"]\n }\n}\n\nvariable \"test3\" {\n type = \"map\"\n default = {\n val1 = {\n val2 = \"hi\"\n }\n }\n}\n\nvariable \"test4\" {\n type = \"map\"\n default = {\n val1 = {\n val2 = [\"hi\"]\n }\n }\n}\n\n# Example of getting an element from a list in a map\noutput \"nestedlist\" {\n value = \"$${element(var.test2[\"val1\"], 0)}\"\n}\n\n# Example of getting an element from a nested map\noutput \"nestedmap\" {\n value = \"$${lookup(var.test3[\"val1\"], \"val2\")}\"\n}" + + primary_package { + acquisition_location = "Server" + package_id = "Test" + feed_id = "${data.octopusdeploy_feeds.feed_octopus_server__built_in_.feeds[0].id}" + + properties = { + "SelectionMode" = "immediate" + } + } + + template { + additional_variable_files = "" + directory = "" + run_automatic_file_substitution = true + target_files = "" + } + + worker_pool_id = octopusdeploy_static_worker_pool.workerpool_docker.id + run_on_server = true + sort_order = 1 + } + + properties = {} + target_roles = [] + } + depends_on = [] +} \ No newline at end of file diff --git a/terraform/50-applyterraformtemplateaction/project_group_test.tf b/terraform/50-applyterraformtemplateaction/project_group_test.tf new file mode 100644 index 000000000..438a4f9c7 --- /dev/null +++ b/terraform/50-applyterraformtemplateaction/project_group_test.tf @@ -0,0 +1,4 @@ +resource "octopusdeploy_project_group" "project_group_test" { + name = "Test" + description = "Test Description" +} diff --git a/terraform/50-applyterraformtemplateaction/provider.tf b/terraform/50-applyterraformtemplateaction/provider.tf new file mode 100644 index 000000000..a04197720 --- /dev/null +++ b/terraform/50-applyterraformtemplateaction/provider.tf @@ -0,0 +1,5 @@ +provider "octopusdeploy" { + address = "${var.octopus_server}" + api_key = "${var.octopus_apikey}" + space_id = "${var.octopus_space_id}" +} diff --git a/terraform/50-applyterraformtemplateaction/provider_vars.tf b/terraform/50-applyterraformtemplateaction/provider_vars.tf new file mode 100644 index 000000000..c7d93fe40 --- /dev/null +++ b/terraform/50-applyterraformtemplateaction/provider_vars.tf @@ -0,0 +1,18 @@ +variable "octopus_server" { + type = string + nullable = false + sensitive = false + description = "The URL of the Octopus server e.g. https://myinstance.octopus.app." +} +variable "octopus_apikey" { + type = string + nullable = false + sensitive = true + description = "The API key used to access the Octopus server. See https://octopus.com/docs/octopus-rest-api/how-to-create-an-api-key for details on creating an API key." +} +variable "octopus_space_id" { + type = string + nullable = false + sensitive = false + description = "The space ID to populate" +} diff --git a/terraform/50-applyterraformtemplateaction/space.tf b/terraform/50-applyterraformtemplateaction/space.tf new file mode 100644 index 000000000..ee59bdc80 --- /dev/null +++ b/terraform/50-applyterraformtemplateaction/space.tf @@ -0,0 +1,3 @@ +output "octopus_space_id" { + value = var.octopus_space_id +} diff --git a/terraform/50-applyterraformtemplateaction/workerpool.tf b/terraform/50-applyterraformtemplateaction/workerpool.tf new file mode 100644 index 000000000..c1fd253fe --- /dev/null +++ b/terraform/50-applyterraformtemplateaction/workerpool.tf @@ -0,0 +1,6 @@ +resource "octopusdeploy_static_worker_pool" "workerpool_docker" { + name = "Docker" + description = "A test worker pool" + is_default = false + sort_order = 3 +}