diff --git a/docs/data-sources/kubernetes_agent_workers.md b/docs/data-sources/kubernetes_agent_workers.md
new file mode 100644
index 000000000..332ac9598
--- /dev/null
+++ b/docs/data-sources/kubernetes_agent_workers.md
@@ -0,0 +1,58 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "octopusdeploy_kubernetes_agent_workers Data Source - terraform-provider-octopusdeploy"
+subcategory: ""
+description: |-
+ Provides information about existing kubernetes agent workers.
+---
+
+# octopusdeploy_kubernetes_agent_workers (Data Source)
+
+Provides information about existing kubernetes agent workers.
+
+
+
+
+## Schema
+
+### Optional
+
+- `health_statuses` (List of String) A filter to search by a list of health statuses of resources. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
+- `ids` (List of String) A filter to search by a list of IDs.
+- `is_disabled` (Boolean) A filter to search by the disabled status of a resource.
+- `name` (String) A filter to search by name.
+- `partial_name` (String) A filter to search by the partial match of a name.
+- `roles` (List of String) A filter to search by a list of role IDs.
+- `shell_names` (List of String) A list of shell names to match in the query and/or search
+- `skip` (Number) A filter to specify the number of items to skip in the response.
+- `space_id` (String) The space ID associated with this resource.
+- `take` (Number) A filter to specify the number of items to take (or return) in the response.
+- `thumbprint` (String) The thumbprint of the deployment target to match in the query and/or search
+
+### Read-Only
+
+- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
+- `kubernetes_agent_workers` (List of Object) A list of kubernetes agent workers that match the filter(s). (see [below for nested schema](#nestedatt--kubernetes_agent_workers))
+
+
+### Nested Schema for `kubernetes_agent_workers`
+
+Read-Only:
+
+- `agent_helm_release_name` (String)
+- `agent_kubernetes_namespace` (String)
+- `agent_tentacle_version` (String)
+- `agent_upgrade_status` (String)
+- `agent_version` (String)
+- `communication_mode` (String)
+- `id` (String)
+- `is_disabled` (Boolean)
+- `machine_policy_id` (String)
+- `name` (String)
+- `space_id` (String)
+- `thumbprint` (String)
+- `upgrade_locked` (Boolean)
+- `uri` (String)
+- `worker_pool_ids` (List of String)
+
+
diff --git a/docs/resources/kubernetes_agent_worker.md b/docs/resources/kubernetes_agent_worker.md
new file mode 100644
index 000000000..436f44c08
--- /dev/null
+++ b/docs/resources/kubernetes_agent_worker.md
@@ -0,0 +1,67 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "octopusdeploy_kubernetes_agent_worker Resource - terraform-provider-octopusdeploy"
+subcategory: ""
+description: |-
+ This resource manages Kubernetes agent workers in Octopus Deploy.
+---
+
+# octopusdeploy_kubernetes_agent_worker (Resource)
+
+This resource manages Kubernetes agent workers in Octopus Deploy.
+
+## Example Usage
+
+```terraform
+resource "octopusdeploy_kubernetes_agent_worker" "minimal" {
+ name = "agent-minimal"
+ worker_pools = ["worker-pools-1"]
+ thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
+ uri = "poll://kcxzcv2fpsxkn6tk9u6d/"
+}
+
+resource "octopusdeploy_kubernetes_agent_worker" "optionals" {
+ name = "agent-optionals"
+ worker_pools = ["worker-pools-1", "worker-pools-3"]
+ thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
+ uri = "poll://kcxzcv2fpsxkn6tk9u6d/"
+ machine_policy_id = "machinepolicies-1"
+ upgrade_locked = true
+ is_disabled = true
+}
+```
+
+
+## Schema
+
+### Required
+
+- `name` (String) The name of this resource.
+- `thumbprint` (String) The thumbprint of the Kubernetes agent's certificate used by server to verify the identity of the agent. This is the same thumbprint that was used when installing the agent.
+- `uri` (String) The URI of the Kubernetes agent's used by the server to queue messages. This is the same subscription uri that was used when installing the agent.
+- `worker_pool_ids` (List of String) A list of worker pool Ids specifying the pools in which this worker belongs
+
+### Optional
+
+- `communication_mode` (String) The communication mode used by the Kubernetes agent to communicate with Octopus Server. Currently, the only supported value is 'Polling'.
+- `id` (String) The unique ID for this resource.
+- `is_disabled` (Boolean) Whether the Kubernetes agent is disabled. If the agent is disabled, it will not be included in any deployments.
+- `machine_policy_id` (String) Optional ID of the machine policy that the Kubernetes agent will use. If not provided the default machine policy will be used.
+- `space_id` (String) The space ID associated with this resource.
+- `upgrade_locked` (Boolean) If enabled the Kubernetes agent will not automatically upgrade and will stay on the currently installed version, even if the associated machine policy is configured to automatically upgrade.
+
+### Read-Only
+
+- `agent_helm_release_name` (String) Name of the Helm release that the agent belongs to.
+- `agent_kubernetes_namespace` (String) Name of the Kubernetes namespace where the agent is installed.
+- `agent_tentacle_version` (String) Current Tentacle version of the agent
+- `agent_upgrade_status` (String) Current upgrade availability status of the agent. One of 'NoUpgrades', 'UpgradeAvailable', 'UpgradeSuggested', 'UpgradeRequired'
+- `agent_version` (String) Current Helm chart version of the agent.
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import [options] octopusdeploy_kubernetes_agent_worker.
+```
diff --git a/examples/resources/octopusdeploy_kubernetes_agent_worker/import.sh b/examples/resources/octopusdeploy_kubernetes_agent_worker/import.sh
new file mode 100644
index 000000000..f3165103d
--- /dev/null
+++ b/examples/resources/octopusdeploy_kubernetes_agent_worker/import.sh
@@ -0,0 +1 @@
+terraform import [options] octopusdeploy_kubernetes_agent_worker.
\ No newline at end of file
diff --git a/examples/resources/octopusdeploy_kubernetes_agent_worker/resource.tf b/examples/resources/octopusdeploy_kubernetes_agent_worker/resource.tf
new file mode 100644
index 000000000..92fd1669b
--- /dev/null
+++ b/examples/resources/octopusdeploy_kubernetes_agent_worker/resource.tf
@@ -0,0 +1,16 @@
+resource "octopusdeploy_kubernetes_agent_worker" "minimal" {
+ name = "agent-minimal"
+ worker_pools = ["worker-pools-1"]
+ thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
+ uri = "poll://kcxzcv2fpsxkn6tk9u6d/"
+}
+
+resource "octopusdeploy_kubernetes_agent_worker" "optionals" {
+ name = "agent-optionals"
+ worker_pools = ["worker-pools-1", "worker-pools-3"]
+ thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
+ uri = "poll://kcxzcv2fpsxkn6tk9u6d/"
+ machine_policy_id = "machinepolicies-1"
+ upgrade_locked = true
+ is_disabled = true
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index cd8a3a059..1d574617d 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/OctopusDeploy/terraform-provider-octopusdeploy
go 1.21
require (
- github.com/OctopusDeploy/go-octopusdeploy/v2 v2.49.2
+ github.com/OctopusDeploy/go-octopusdeploy/v2 v2.50.0
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
diff --git a/go.sum b/go.sum
index cfe020223..066bca243 100644
--- a/go.sum
+++ b/go.sum
@@ -20,8 +20,8 @@ github.com/Microsoft/hcsshim v0.12.4 h1:Ev7YUMHAHoWNm+aDSPzc5W9s6E2jyL1szpVDJeZ/
github.com/Microsoft/hcsshim v0.12.4/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ=
github.com/OctopusDeploy/go-octodiff v1.0.0 h1:U+ORg6azniwwYo+O44giOw6TiD5USk8S4VDhOQ0Ven0=
github.com/OctopusDeploy/go-octodiff v1.0.0/go.mod h1:Mze0+EkOWTgTmi8++fyUc6r0aLZT7qD9gX+31t8MmIU=
-github.com/OctopusDeploy/go-octopusdeploy/v2 v2.49.2 h1:ENd1MyQbYIDiW1ZyXRUcZr4OQ0d8j47I5a6DOT9Ez4o=
-github.com/OctopusDeploy/go-octopusdeploy/v2 v2.49.2/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
+github.com/OctopusDeploy/go-octopusdeploy/v2 v2.50.0 h1:rQiLEbqt/D3lPQw3pq9sXAW1C0WhVLrfN/h0cqUzaFY=
+github.com/OctopusDeploy/go-octopusdeploy/v2 v2.50.0/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4 h1:QfbVf0bOIRMp/WHAWsuVDB7KHoWnRsGbvDuOf2ua7k4=
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4/go.mod h1:Oq9KbiRNDBB5jFmrwnrgLX0urIqR/1ptY18TzkqXm7M=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
diff --git a/octopusdeploy/data_source_kubernetes_agent_workers.go b/octopusdeploy/data_source_kubernetes_agent_workers.go
new file mode 100644
index 000000000..c270d7c3e
--- /dev/null
+++ b/octopusdeploy/data_source_kubernetes_agent_workers.go
@@ -0,0 +1,51 @@
+package octopusdeploy
+
+import (
+ "context"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "time"
+)
+
+func dataSourceKubernetesAgentWorkers() *schema.Resource {
+ return &schema.Resource{
+ Description: "Provides information about existing kubernetes agent workers.",
+ ReadContext: dataSourceKubernetesAgentWorkersRead,
+ Schema: getKubernetesAgentWorkerDataSchema(),
+ }
+}
+
+func dataSourceKubernetesAgentWorkersRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ query := machines.WorkersQuery{
+ CommunicationStyles: []string{"KubernetesTentacle"},
+ HealthStatuses: expandArray(d.Get("health_statuses").([]interface{})),
+ IDs: expandArray(d.Get("ids").([]interface{})),
+ IsDisabled: d.Get("is_disabled").(bool),
+ Name: d.Get("name").(string),
+ PartialName: d.Get("partial_name").(string),
+ ShellNames: expandArray(d.Get("shell_names").([]interface{})),
+ Skip: d.Get("skip").(int),
+ Take: d.Get("take").(int),
+ Thumbprint: d.Get("thumbprint").(string),
+ }
+
+ client := m.(*client.Client)
+ existingWorkers, err := client.Workers.Get(query)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ flattenedKubernetesAgents := []interface{}{}
+ for _, worker := range existingWorkers.Items {
+ flattenedKubernetesAgents = append(flattenedKubernetesAgents, flattenKubernetesAgentWorker(worker))
+ }
+
+ err = d.Set("kubernetes_agent_workers", flattenedKubernetesAgents)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ d.SetId("KubernetesAgentWorkers " + time.Now().UTC().String())
+ return nil
+}
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index a5f8061cb..5f1a0822f 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -19,6 +19,7 @@ func Provider() *schema.Provider {
"octopusdeploy_channels": dataSourceChannels(),
"octopusdeploy_deployment_targets": dataSourceDeploymentTargets(),
"octopusdeploy_kubernetes_agent_deployment_targets": dataSourceKubernetesAgentDeploymentTargets(),
+ "octopusdeploy_kubernetes_agent_workers": dataSourceKubernetesAgentWorkers(),
"octopusdeploy_kubernetes_cluster_deployment_targets": dataSourceKubernetesClusterDeploymentTargets(),
"octopusdeploy_listening_tentacle_deployment_targets": dataSourceListeningTentacleDeploymentTargets(),
"octopusdeploy_machine": dataSourceMachine(),
@@ -47,6 +48,7 @@ func Provider() *schema.Provider {
"octopusdeploy_dynamic_worker_pool": resourceDynamicWorkerPool(),
"octopusdeploy_gcp_account": resourceGoogleCloudPlatformAccount(),
"octopusdeploy_kubernetes_agent_deployment_target": resourceKubernetesAgentDeploymentTarget(),
+ "octopusdeploy_kubernetes_agent_worker": resourceKubernetesAgentWorker(),
"octopusdeploy_kubernetes_cluster_deployment_target": resourceKubernetesClusterDeploymentTarget(),
"octopusdeploy_listening_tentacle_deployment_target": resourceListeningTentacleDeploymentTarget(),
"octopusdeploy_machine_policy": resourceMachinePolicy(),
diff --git a/octopusdeploy/resource_kubernetes_agent_worker.go b/octopusdeploy/resource_kubernetes_agent_worker.go
new file mode 100644
index 000000000..e761f3e13
--- /dev/null
+++ b/octopusdeploy/resource_kubernetes_agent_worker.go
@@ -0,0 +1,79 @@
+package octopusdeploy
+
+import (
+ "context"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/workers"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceKubernetesAgentWorker() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: resourceKubernetesAgentWorkerCreate,
+ DeleteContext: resourceKubernetesAgentWorkerDelete,
+ Description: "This resource manages Kubernetes agent workers in Octopus Deploy.",
+ Importer: getImporter(),
+ ReadContext: resourceKubernetesAgentWorkerRead,
+ Schema: getKubernetesAgentWorkerSchema(),
+ UpdateContext: resourceKubernetesAgentWorkerUpdate,
+ }
+}
+
+func resourceKubernetesAgentWorkerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ worker := expandKubernetesAgentWorker(d)
+ client := m.(*client.Client)
+ createdWorker, err := workers.Add(client, worker)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ d.SetId(createdWorker.GetID())
+ return nil
+}
+
+func resourceKubernetesAgentWorkerRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ client := m.(*client.Client)
+ Worker, err := workers.GetByID(client, d.Get("space_id").(string), d.Id())
+ if err != nil {
+ return errors.ProcessApiError(ctx, d, err, "kubernetes tentacle worker")
+ }
+
+ flattenedKubernetesAgentWorker := flattenKubernetesAgentWorker(Worker)
+ for key, value := range flattenedKubernetesAgentWorker {
+ if key != "id" {
+ err := d.Set(key, value)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
+ }
+
+ return nil
+}
+
+func resourceKubernetesAgentWorkerDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ client := m.(*client.Client)
+ if err := workers.DeleteByID(client, d.Get("space_id").(string), d.Id()); err != nil {
+ return diag.FromErr(err)
+ }
+ d.SetId("")
+ return nil
+}
+
+func resourceKubernetesAgentWorkerUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ worker := expandKubernetesAgentWorker(d)
+ client := m.(*client.Client)
+
+ worker.ID = d.Id()
+
+ updatedWorker, err := workers.Update(client, worker)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ d.SetId(updatedWorker.GetID())
+
+ return nil
+}
diff --git a/octopusdeploy/resource_kubernetes_agent_worker_integration_test.go b/octopusdeploy/resource_kubernetes_agent_worker_integration_test.go
new file mode 100644
index 000000000..d6c109563
--- /dev/null
+++ b/octopusdeploy/resource_kubernetes_agent_worker_integration_test.go
@@ -0,0 +1,107 @@
+package octopusdeploy
+
+import (
+ "context"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines"
+ "github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
+ "github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
+ "log"
+ "os"
+ "path/filepath"
+ stdslices "slices"
+ "testing"
+ "time"
+)
+
+func TestKubernetesAgentWorkerResource(t *testing.T) {
+ testFramework := test.OctopusContainerTest{
+ CustomEnvironment: map[string]string{
+ "OCTOPUS__FeatureToggles__KubernetesAgentAsWorkerFeatureToggle": "true",
+ },
+ }
+
+ // Use separate Octopus container as this test requires a custom environment variable to be set
+ testSpecificOctoContainer, _, testSpecificSqlServerContainer, testSpecificNetwork, err := testFramework.ArrangeContainer()
+ if err != nil {
+ log.Printf("Failed to arrange containers: (%s)", err.Error())
+ }
+ os.Setenv("TF_ACC", "1")
+
+ inputVars := []string{"-var=octopus_server_58-kubernetesagentworker=" + testSpecificOctoContainer.URI, "-var=octopus_apikey_58-kubernetesagentworker=" + test.ApiKey}
+
+ newSpaceId, err := testFramework.Act(t, testSpecificOctoContainer, "../terraform", "58-kubernetesagentworker", inputVars)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+
+ err = testFramework.TerraformInitAndApply(t, testSpecificOctoContainer, filepath.Join("../terraform", "58a-kubernetesagentworkerds"), newSpaceId, inputVars)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+
+ // Assert
+ client, err := octoclient.CreateClient(testSpecificOctoContainer.URI, newSpaceId, test.ApiKey)
+ query := machines.WorkersQuery{
+ CommunicationStyles: []string{"KubernetesTentacle"},
+ Skip: 0,
+ Take: 3,
+ }
+
+ resources, err := client.Workers.Get(query)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+
+ if len(resources.Items) != 2 {
+ t.Fatalf("Space must have two workers (both KubernetesTentacles), instead found %v", resources.Items)
+ }
+
+ minimalAgentName := "minimum-agent"
+ minimalAgentIndex := stdslices.IndexFunc(resources.Items, func(t *machines.Worker) bool { return t.Name == minimalAgentName })
+ minimalAgentWorker := resources.Items[minimalAgentIndex]
+ minimalAgentEndpoint := minimalAgentWorker.Endpoint.(*machines.KubernetesTentacleEndpoint)
+ if minimalAgentWorker.IsDisabled {
+ t.Fatalf("Expected \"%s\" to be enabled", minimalAgentName)
+ }
+
+ if minimalAgentEndpoint.UpgradeLocked {
+ t.Fatalf("Expected \"%s\" to not be upgrade locked", minimalAgentName)
+ }
+
+ if len(minimalAgentWorker.WorkerPoolIDs) != 1 {
+ t.Fatalf("Expected \"%s\" to have one worker pool id", minimalAgentName)
+ }
+
+ fullAgentName := "agent-with-optionals"
+ fullAgentIndex := stdslices.IndexFunc(resources.Items, func(t *machines.Worker) bool { return t.Name == fullAgentName })
+ fullAgentWorker := resources.Items[fullAgentIndex]
+
+ if !fullAgentWorker.IsDisabled {
+ t.Fatalf("Expected \"%s\" to be disabled", fullAgentName)
+ }
+
+ fullAgentEndpoint := fullAgentWorker.Endpoint.(*machines.KubernetesTentacleEndpoint)
+ if !fullAgentEndpoint.UpgradeLocked {
+ t.Fatalf("Expected \"%s\" to be upgrade locked", fullAgentName)
+ }
+
+ if len(fullAgentWorker.WorkerPoolIDs) != 2 {
+ t.Fatalf("Expected \"%s\" to have two worker pool ids", fullAgentName)
+ }
+
+ _, err = testFramework.GetOutputVariable(t, filepath.Join("../terraform", "58a-kubernetesagentworkerds"), "data_lookup_kubernetes_worker_1_id")
+ _, err = testFramework.GetOutputVariable(t, filepath.Join("../terraform", "58a-kubernetesagentworkerds"), "data_lookup_kubernetes_worker_2_id")
+ if err != nil {
+ t.Fatal("Failed to query for created k8s workers")
+ }
+
+ ctx := context.Background()
+
+ // Waiting for the container logs to clear.
+ time.Sleep(5000 * time.Millisecond)
+ err = testFramework.CleanUp(ctx, testSpecificOctoContainer, testSpecificSqlServerContainer, testSpecificNetwork)
+
+ if err != nil {
+ log.Printf("Failed to clean up containers: (%s)", err.Error())
+ }
+}
diff --git a/octopusdeploy/schema_kubernetes_agent_worker.go b/octopusdeploy/schema_kubernetes_agent_worker.go
new file mode 100644
index 000000000..8c6f1e753
--- /dev/null
+++ b/octopusdeploy/schema_kubernetes_agent_worker.go
@@ -0,0 +1,157 @@
+package octopusdeploy
+
+import (
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+ "net/url"
+)
+
+func expandKubernetesAgentWorker(kubernetesAgent *schema.ResourceData) *machines.Worker {
+ uri, _ := url.Parse(kubernetesAgent.Get("uri").(string))
+ thumbprint := kubernetesAgent.Get("thumbprint").(string)
+
+ communicationsMode := kubernetesAgent.Get("communication_mode").(string)
+ upgradeLocked := kubernetesAgent.Get("upgrade_locked").(bool)
+ var endpoint machines.IEndpoint = machines.NewKubernetesTentacleEndpoint(uri, thumbprint, upgradeLocked, communicationsMode, "")
+
+ name := kubernetesAgent.Get("name").(string)
+ Worker := machines.NewWorker(name, endpoint)
+
+ Worker.IsDisabled = kubernetesAgent.Get("is_disabled").(bool)
+ Worker.Thumbprint = thumbprint
+ Worker.WorkerPoolIDs = getSliceFromTerraformTypeList(kubernetesAgent.Get("worker_pool_ids"))
+
+ Worker.SpaceID = kubernetesAgent.Get("space_id").(string)
+
+ return Worker
+}
+
+func flattenKubernetesAgentWorker(Worker *machines.Worker) map[string]interface{} {
+ if Worker == nil {
+ return nil
+ }
+
+ if Worker.Endpoint.GetCommunicationStyle() != "KubernetesTentacle" {
+ return nil
+ }
+
+ endpoint := Worker.Endpoint.(*machines.KubernetesTentacleEndpoint)
+
+ flattenedWorker := map[string]interface{}{}
+ flattenedWorker["id"] = Worker.GetID()
+ flattenedWorker["space_id"] = Worker.SpaceID
+ flattenedWorker["name"] = Worker.Name
+ flattenedWorker["machine_policy_id"] = Worker.MachinePolicyID
+ flattenedWorker["is_disabled"] = Worker.IsDisabled
+
+ flattenedWorker["thumbprint"] = endpoint.TentacleEndpointConfiguration.Thumbprint
+ flattenedWorker["uri"] = endpoint.TentacleEndpointConfiguration.URI.String()
+ flattenedWorker["communication_mode"] = endpoint.TentacleEndpointConfiguration.CommunicationMode
+ flattenedWorker["worker_pool_ids"] = Worker.WorkerPoolIDs
+
+ if endpoint.KubernetesAgentDetails != nil {
+ flattenedWorker["agent_version"] = endpoint.KubernetesAgentDetails.AgentVersion
+ flattenedWorker["agent_tentacle_version"] = endpoint.KubernetesAgentDetails.TentacleVersion
+ flattenedWorker["agent_upgrade_status"] = endpoint.KubernetesAgentDetails.UpgradeStatus
+ flattenedWorker["agent_helm_release_name"] = endpoint.KubernetesAgentDetails.HelmReleaseName
+ flattenedWorker["agent_kubernetes_namespace"] = endpoint.KubernetesAgentDetails.KubernetesNamespace
+ }
+
+ return flattenedWorker
+}
+
+func getKubernetesAgentWorkerSchema() map[string]*schema.Schema {
+ return map[string]*schema.Schema{
+ "id": getIDSchema(),
+ "space_id": getSpaceIDSchema(),
+ "name": getNameSchema(true),
+ "communication_mode": {
+ Optional: true,
+ Description: "The communication mode used by the Kubernetes agent to communicate with Octopus Server. Currently, the only supported value is 'Polling'.",
+ Type: schema.TypeString,
+ Default: "Polling",
+ ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{"Polling"}, false)),
+ },
+ "machine_policy_id": {
+ Description: "Optional ID of the machine policy that the Kubernetes agent will use. If not provided the default machine policy will be used.",
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeString,
+ },
+ "thumbprint": {
+ Description: "The thumbprint of the Kubernetes agent's certificate used by server to verify the identity of the agent. This is the same thumbprint that was used when installing the agent.",
+ Required: true,
+ Type: schema.TypeString,
+ },
+ "uri": {
+ Description: "The URI of the Kubernetes agent's used by the server to queue messages. This is the same subscription uri that was used when installing the agent.",
+ Required: true,
+ Type: schema.TypeString,
+ },
+ "upgrade_locked": {
+ Description: "If enabled the Kubernetes agent will not automatically upgrade and will stay on the currently installed version, even if the associated machine policy is configured to automatically upgrade.",
+ Optional: true,
+ Type: schema.TypeBool,
+ },
+ "is_disabled": {
+ Description: "Whether the Kubernetes agent is disabled. If the agent is disabled, it will not be included in any deployments.",
+ Optional: true,
+ Default: false,
+ Type: schema.TypeBool,
+ },
+ "worker_pool_ids": {
+ Description: "A list of worker pool Ids specifying the pools in which this worker belongs",
+ Elem: &schema.Schema{Type: schema.TypeString},
+ MinItems: 1,
+ Required: true,
+ Type: schema.TypeList,
+ },
+
+ // Read-only Values
+ "agent_version": {
+ Description: "Current Helm chart version of the agent.",
+ Computed: true,
+ Type: schema.TypeString,
+ },
+ "agent_tentacle_version": {
+ Description: "Current Tentacle version of the agent",
+ Computed: true,
+ Type: schema.TypeString,
+ },
+ "agent_upgrade_status": {
+ Description: "Current upgrade availability status of the agent. One of 'NoUpgrades', 'UpgradeAvailable', 'UpgradeSuggested', 'UpgradeRequired'",
+ Computed: true,
+ Type: schema.TypeString,
+ },
+ "agent_helm_release_name": {
+ Description: "Name of the Helm release that the agent belongs to.",
+ Computed: true,
+ Type: schema.TypeString,
+ },
+ "agent_kubernetes_namespace": {
+ Description: "Name of the Kubernetes namespace where the agent is installed.",
+ Computed: true,
+ Type: schema.TypeString,
+ },
+ }
+}
+
+func getKubernetesAgentWorkerDataSchema() map[string]*schema.Schema {
+ dataSchema := getKubernetesAgentWorkerSchema()
+ setDataSchema(&dataSchema)
+
+ WorkerDataSchema := getWorkerDataSchema()
+ WorkerDataSchema["kubernetes_agent_workers"] = &schema.Schema{
+ Computed: true,
+ Description: "A list of kubernetes agent workers that match the filter(s).",
+ Elem: &schema.Resource{Schema: dataSchema},
+ Optional: false,
+ Type: schema.TypeList,
+ }
+
+ delete(WorkerDataSchema, "communication_styles")
+ delete(WorkerDataSchema, "workers")
+ WorkerDataSchema["id"] = getDataSchemaID()
+ return WorkerDataSchema
+}
diff --git a/octopusdeploy/schema_worker.go b/octopusdeploy/schema_worker.go
new file mode 100644
index 000000000..56822960a
--- /dev/null
+++ b/octopusdeploy/schema_worker.go
@@ -0,0 +1,201 @@
+package octopusdeploy
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func expandWorker(d *schema.ResourceData) *machines.Worker {
+ endpoint := expandEndpoint(d.Get("endpoint"))
+ name := d.Get("name").(string)
+
+ worker := machines.NewWorker(name, endpoint)
+ worker.ID = d.Id()
+
+ if v, ok := d.GetOk("machine_policy_id"); ok {
+ worker.MachinePolicyID = v.(string)
+ }
+
+ if v, ok := d.GetOk("is_disabled"); ok {
+ worker.IsDisabled = v.(bool)
+ }
+
+ if v, ok := d.GetOk("thumbprint"); ok {
+ worker.Thumbprint = v.(string)
+ }
+
+ if v, ok := d.GetOk("uri"); ok {
+ worker.URI = v.(string)
+ }
+
+ if v, ok := d.GetOk("space_id"); ok {
+ worker.SpaceID = v.(string)
+ }
+
+ if v, ok := d.GetOk("thumbprint"); ok {
+ worker.Thumbprint = v.(string)
+ }
+
+ worker.WorkerPoolIDs = getSliceFromTerraformTypeList(d.Get("worker_pool_ids"))
+
+ return worker
+}
+
+func flattenWorker(worker *machines.Worker) map[string]interface{} {
+ if worker == nil {
+ return nil
+ }
+
+ endpointResource, _ := machines.ToEndpointResource(worker.Endpoint)
+
+ return map[string]interface{}{
+ "endpoint": flattenEndpointResource(endpointResource),
+ "has_latest_calamari": worker.HasLatestCalamari,
+ "health_status": worker.HealthStatus,
+ "id": worker.GetID(),
+ "is_disabled": worker.IsDisabled,
+ "is_in_process": worker.IsInProcess,
+ "machine_policy_id": worker.MachinePolicyID,
+ "name": worker.Name,
+ "operating_system": worker.OperatingSystem,
+ "shell_name": worker.ShellName,
+ "shell_version": worker.ShellVersion,
+ "space_id": worker.SpaceID,
+ "status": worker.Status,
+ "status_summary": worker.StatusSummary,
+ "thumbprint": worker.Thumbprint,
+ "uri": worker.URI,
+ "worker_pool_ids": worker.WorkerPoolIDs,
+ }
+}
+
+func getWorkerDataSchema() map[string]*schema.Schema {
+ dataSchema := getWorkerSchema()
+ setDataSchema(&dataSchema)
+
+ return map[string]*schema.Schema{
+ "communication_styles": getQueryCommunicationStyles(),
+ "workers": {
+ Computed: true,
+ Description: "A list of workers that match the filter(s).",
+ Elem: &schema.Resource{Schema: dataSchema},
+ Optional: true,
+ Type: schema.TypeList,
+ },
+ "health_statuses": getQueryHealthStatuses(),
+ "ids": getQueryIDs(),
+ "is_disabled": getQueryIsDisabled(),
+ "name": getQueryName(),
+ "partial_name": getQueryPartialName(),
+ "roles": getQueryRoles(),
+ "shell_names": getQueryShellNames(),
+ "skip": getQuerySkip(),
+ "take": getQueryTake(),
+ "thumbprint": getQueryThumbprint(),
+ "space_id": getSpaceIDSchema(),
+ }
+}
+
+func getWorkerSchema() map[string]*schema.Schema {
+ return map[string]*schema.Schema{
+ "endpoint": {
+ Computed: true,
+ Elem: &schema.Resource{Schema: getEndpointSchema()},
+ MinItems: 1,
+ Optional: true,
+ Type: schema.TypeList,
+ },
+ "has_latest_calamari": {
+ Computed: true,
+ Type: schema.TypeBool,
+ },
+ "health_status": getHealthStatusSchema(),
+ "id": getIDSchema(),
+ "is_disabled": {
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeBool,
+ },
+ "is_in_process": {
+ Computed: true,
+ Type: schema.TypeBool,
+ },
+ "machine_policy_id": {
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeString,
+ },
+ "name": getNameSchema(true),
+ "operating_system": {
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeString,
+ },
+ "shell_name": {
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeString,
+ },
+ "shell_version": {
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeString,
+ },
+ "space_id": getSpaceIDSchema(),
+ "status": getStatusSchema(),
+ "status_summary": getStatusSummarySchema(),
+ "thumbprint": {
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeString,
+ },
+ "uri": {
+ Computed: true,
+ Optional: true,
+ Type: schema.TypeString,
+ },
+ "worker_pool_ids": {
+ Elem: &schema.Schema{Type: schema.TypeString},
+ MinItems: 1,
+ Required: true,
+ Type: schema.TypeList,
+ },
+ }
+}
+
+func setWorker(ctx context.Context, d *schema.ResourceData, worker *machines.Worker) error {
+ d.Set("has_latest_calamari", worker.HasLatestCalamari)
+ d.Set("health_status", worker.HealthStatus)
+ d.Set("is_disabled", worker.IsDisabled)
+ d.Set("is_in_process", worker.IsInProcess)
+ d.Set("machine_policy_id", worker.MachinePolicyID)
+ d.Set("name", worker.Name)
+ d.Set("operating_system", worker.OperatingSystem)
+ d.Set("shell_name", worker.ShellName)
+ d.Set("shell_version", worker.ShellVersion)
+ d.Set("space_id", worker.SpaceID)
+ d.Set("status", worker.Status)
+ d.Set("status_summary", worker.StatusSummary)
+ d.Set("thumbprint", worker.Thumbprint)
+ d.Set("uri", worker.URI)
+ d.Set("space_id", worker.SpaceID)
+ d.Set("worker_pool_ids", worker.WorkerPoolIDs)
+
+ endpointResource, err := machines.ToEndpointResource(worker.Endpoint)
+ if err != nil {
+ return fmt.Errorf("error setting endpoint: %s", err)
+ }
+
+ if d.Get("endpoint") != nil {
+ if err := d.Set("endpoint", flattenEndpointResource(endpointResource)); err != nil {
+ return fmt.Errorf("error setting endpoint: %s", err)
+ }
+ }
+
+ d.SetId(worker.GetID())
+
+ return nil
+}
diff --git a/terraform/58-kubernetesagentworker/config.tf b/terraform/58-kubernetesagentworker/config.tf
new file mode 100644
index 000000000..2113da144
--- /dev/null
+++ b/terraform/58-kubernetesagentworker/config.tf
@@ -0,0 +1,5 @@
+terraform {
+ required_providers {
+ octopusdeploy = { source = "OctopusDeployLabs/octopusdeploy", version = "0.18.1" }
+ }
+}
diff --git a/terraform/58-kubernetesagentworker/kubernetes_agent_workers.tf b/terraform/58-kubernetesagentworker/kubernetes_agent_workers.tf
new file mode 100644
index 000000000..dfec82c37
--- /dev/null
+++ b/terraform/58-kubernetesagentworker/kubernetes_agent_workers.tf
@@ -0,0 +1,17 @@
+resource "octopusdeploy_kubernetes_agent_worker" "agent_with_minimum" {
+ name = "minimum-agent"
+ worker_pool_ids = [octopusdeploy_static_worker_pool.workerpool_docker.id]
+ uri = "poll://kcxzcv2fpsxkn6tk9u6d/"
+ thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
+}
+
+resource "octopusdeploy_kubernetes_agent_worker" "agent_with_optional" {
+ name = "agent-with-optionals"
+ machine_policy_id = octopusdeploy_machine_policy.machinepolicy_testing.id
+ worker_pool_ids = [octopusdeploy_static_worker_pool.workerpool_docker.id, octopusdeploy_static_worker_pool.workerpool_example.id]
+ communication_mode = "Polling"
+ uri = "poll://kcxzcv2fpsxkn6tk9u6d/"
+ thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
+ is_disabled = true
+ upgrade_locked = true
+}
\ No newline at end of file
diff --git a/terraform/58-kubernetesagentworker/machinepolicy.tf b/terraform/58-kubernetesagentworker/machinepolicy.tf
new file mode 100644
index 000000000..b3ef159d8
--- /dev/null
+++ b/terraform/58-kubernetesagentworker/machinepolicy.tf
@@ -0,0 +1,39 @@
+resource "octopusdeploy_machine_policy" "machinepolicy_testing" {
+ name = "Testing"
+ description = "test machine policy"
+ connection_connect_timeout = 60000000000
+ connection_retry_count_limit = 5
+ connection_retry_sleep_interval = 100000000
+ connection_retry_time_limit = 300000000000
+
+ machine_cleanup_policy {
+ delete_machines_behavior = "DeleteUnavailableMachines"
+ delete_machines_elapsed_timespan = 1200000000000
+ }
+
+ machine_connectivity_policy {
+ machine_connectivity_behavior = "ExpectedToBeOnline"
+ }
+
+ machine_health_check_policy {
+
+ bash_health_check_policy {
+ run_type = "Inline"
+ script_body = ""
+ }
+
+ powershell_health_check_policy {
+ run_type = "Inline"
+ script_body = "$freeDiskSpaceThreshold = 5GB\r\n\r\nTry {\r\n\tGet-WmiObject win32_LogicalDisk -ErrorAction Stop | ? { ($_.DriveType -eq 3) -and ($_.FreeSpace -ne $null)} | % { CheckDriveCapacity @{Name =$_.DeviceId; FreeSpace=$_.FreeSpace} }\r\n} Catch [System.Runtime.InteropServices.COMException] {\r\n\tGet-WmiObject win32_Volume | ? { ($_.DriveType -eq 3) -and ($_.FreeSpace -ne $null) -and ($_.DriveLetter -ne $null)} | % { CheckDriveCapacity @{Name =$_.DriveLetter; FreeSpace=$_.FreeSpace} }\r\n\tGet-WmiObject Win32_MappedLogicalDisk | ? { ($_.FreeSpace -ne $null) -and ($_.DeviceId -ne $null)} | % { CheckDriveCapacity @{Name =$_.DeviceId; FreeSpace=$_.FreeSpace} }\t\r\n}"
+ }
+
+ health_check_cron_timezone = "UTC"
+ health_check_interval = 600000000000
+ health_check_type = "RunScript"
+ }
+
+ machine_update_policy {
+ calamari_update_behavior = "UpdateOnDeployment"
+ tentacle_update_behavior = "NeverUpdate"
+ }
+}
\ No newline at end of file
diff --git a/terraform/58-kubernetesagentworker/provider.tf b/terraform/58-kubernetesagentworker/provider.tf
new file mode 100644
index 000000000..d563e69b0
--- /dev/null
+++ b/terraform/58-kubernetesagentworker/provider.tf
@@ -0,0 +1,5 @@
+provider "octopusdeploy" {
+ address = "${var.octopus_server_58-kubernetesagentworker}"
+ api_key = "${var.octopus_apikey_58-kubernetesagentworker}"
+ space_id = "${var.octopus_space_id}"
+}
diff --git a/terraform/58-kubernetesagentworker/provider_vars.tf b/terraform/58-kubernetesagentworker/provider_vars.tf
new file mode 100644
index 000000000..96be8b1f5
--- /dev/null
+++ b/terraform/58-kubernetesagentworker/provider_vars.tf
@@ -0,0 +1,30 @@
+variable "octopus_server" {
+ type = string
+ nullable = false
+ sensitive = false
+ description = "Not used for this test but need to be declared"
+}
+variable "octopus_apikey" {
+ type = string
+ nullable = false
+ sensitive = true
+ description = "Not used for this test but need to be declared"
+}
+variable "octopus_server_58-kubernetesagentworker" {
+ type = string
+ nullable = false
+ sensitive = false
+ description = "The URL of the Octopus server e.g. https://myinstance.octopus.app."
+}
+variable "octopus_apikey_58-kubernetesagentworker" {
+ 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/58-kubernetesagentworker/space.tf b/terraform/58-kubernetesagentworker/space.tf
new file mode 100644
index 000000000..ee59bdc80
--- /dev/null
+++ b/terraform/58-kubernetesagentworker/space.tf
@@ -0,0 +1,3 @@
+output "octopus_space_id" {
+ value = var.octopus_space_id
+}
diff --git a/terraform/58-kubernetesagentworker/workerpool.tf b/terraform/58-kubernetesagentworker/workerpool.tf
new file mode 100644
index 000000000..a8ff2d101
--- /dev/null
+++ b/terraform/58-kubernetesagentworker/workerpool.tf
@@ -0,0 +1,13 @@
+resource "octopusdeploy_static_worker_pool" "workerpool_docker" {
+ name = "Docker"
+ description = "A test worker pool"
+ is_default = false
+ sort_order = 3
+}
+
+resource "octopusdeploy_static_worker_pool" "workerpool_example" {
+ name = "Example"
+ description = "My other example worker pool"
+ is_default = false
+ sort_order = 4
+}
diff --git a/terraform/58a-kubernetesagentworkerds/config.tf b/terraform/58a-kubernetesagentworkerds/config.tf
new file mode 100644
index 000000000..2113da144
--- /dev/null
+++ b/terraform/58a-kubernetesagentworkerds/config.tf
@@ -0,0 +1,5 @@
+terraform {
+ required_providers {
+ octopusdeploy = { source = "OctopusDeployLabs/octopusdeploy", version = "0.18.1" }
+ }
+}
diff --git a/terraform/58a-kubernetesagentworkerds/kubernetes_agent_workers.tf b/terraform/58a-kubernetesagentworkerds/kubernetes_agent_workers.tf
new file mode 100644
index 000000000..f3bad68eb
--- /dev/null
+++ b/terraform/58a-kubernetesagentworkerds/kubernetes_agent_workers.tf
@@ -0,0 +1,10 @@
+data "octopusdeploy_kubernetes_agent_workers" "all_workers" {
+}
+
+output "data_lookup_kubernetes_worker_1_id" {
+ value = data.octopusdeploy_kubernetes_agent_workers.all_workers.kubernetes_agent_workers[0].id
+}
+
+output "data_lookup_kubernetes_worker_2_id" {
+ value = data.octopusdeploy_kubernetes_agent_workers.all_workers.kubernetes_agent_workers[1].id
+}
\ No newline at end of file
diff --git a/terraform/58a-kubernetesagentworkerds/provider.tf b/terraform/58a-kubernetesagentworkerds/provider.tf
new file mode 100644
index 000000000..d563e69b0
--- /dev/null
+++ b/terraform/58a-kubernetesagentworkerds/provider.tf
@@ -0,0 +1,5 @@
+provider "octopusdeploy" {
+ address = "${var.octopus_server_58-kubernetesagentworker}"
+ api_key = "${var.octopus_apikey_58-kubernetesagentworker}"
+ space_id = "${var.octopus_space_id}"
+}
diff --git a/terraform/58a-kubernetesagentworkerds/provider_vars.tf b/terraform/58a-kubernetesagentworkerds/provider_vars.tf
new file mode 100644
index 000000000..96be8b1f5
--- /dev/null
+++ b/terraform/58a-kubernetesagentworkerds/provider_vars.tf
@@ -0,0 +1,30 @@
+variable "octopus_server" {
+ type = string
+ nullable = false
+ sensitive = false
+ description = "Not used for this test but need to be declared"
+}
+variable "octopus_apikey" {
+ type = string
+ nullable = false
+ sensitive = true
+ description = "Not used for this test but need to be declared"
+}
+variable "octopus_server_58-kubernetesagentworker" {
+ type = string
+ nullable = false
+ sensitive = false
+ description = "The URL of the Octopus server e.g. https://myinstance.octopus.app."
+}
+variable "octopus_apikey_58-kubernetesagentworker" {
+ 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/58a-kubernetesagentworkerds/space.tf b/terraform/58a-kubernetesagentworkerds/space.tf
new file mode 100644
index 000000000..ee59bdc80
--- /dev/null
+++ b/terraform/58a-kubernetesagentworkerds/space.tf
@@ -0,0 +1,3 @@
+output "octopus_space_id" {
+ value = var.octopus_space_id
+}