Skip to content

Commit

Permalink
feat: Add listening tentacle worker (#812)
Browse files Browse the repository at this point in the history
  • Loading branch information
denys-octopus authored Nov 13, 2024
1 parent cce0c64 commit 8130400
Show file tree
Hide file tree
Showing 10 changed files with 510 additions and 5 deletions.
6 changes: 3 additions & 3 deletions docs/resources/azure_container_registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
page_title: "octopusdeploy_azure_container_registry Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
This resource manages a Google Container Registry feed in Octopus Deploy (alias of Docker Container Registry feed)
This resource manages Azure Container Registry feed in Octopus Deploy (alias of Docker Container Registry feed)
---

# octopusdeploy_azure_container_registry (Resource)

This resource manages a Google Container Registry feed in Octopus Deploy (alias of Docker Container Registry feed)
This resource manages Azure Container Registry feed in Octopus Deploy (alias of Docker Container Registry feed)

## Example Usage

Expand All @@ -34,7 +34,7 @@ resource "octopusdeploy_azure_container_registry" "example" {
- `api_version` (String)
- `password` (String, Sensitive) The password associated with this resource.
- `registry_path` (String)
- `space_id` (String) The space ID associated with this Google container registry feed.
- `space_id` (String) The space ID associated with this Azure container registry feed.
- `username` (String, Sensitive) The username associated with this resource.

### Read-Only
Expand Down
62 changes: 62 additions & 0 deletions docs/resources/listening_tentacle_worker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "octopusdeploy_listening_tentacle_worker Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
This resource manages a listening tentacle worker in Octopus Deploy.
---

# octopusdeploy_listening_tentacle_worker (Resource)

This resource manages a listening tentacle worker in Octopus Deploy.

## Example Usage

```terraform
resource "octopusdeploy_listening_tentacle_worker" "minimum" {
name = "listening_worker"
machine_policy_id = "machine-policy-1"
worker_pools = ["worker-pools-1", "worker-pools-2"]
thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
uri = "https://tentacle.listening/"
}
resource "octopusdeploy_listening_tentacle_worker" "optionals" {
name = "optional_worker"
machine_policy_id = "machine-policy-1"
worker_pools = ["worker-pools-1"]
thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
uri = "https://tentacle.listening/"
proxy_id = "proxys-1"
is_disabled = true
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `machine_policy_id` (String) Select the machine policy
- `name` (String) The name of this resource.
- `thumbprint` (String) The X509 certificate thumbprint that securely identifies the Tentacle
- `uri` (String) The network address at which the Tentacle can be reached
- `worker_pool_ids` (Set of String) Select at least one worker pool for the worker

### Optional

- `is_disabled` (Boolean) When disabled, worker will not be included in any deployments
- `proxy_id` (String) Specify the connection type for the Tentacle: direct(when not set) or via a proxy server.
- `space_id` (String) The space ID associated with this Listening tentacle worker.

### Read-Only

- `id` (String) The unique ID for this resource.

## Import

Import is supported using the following syntax:

```shell
terraform import [options] octopusdeploy_listening_tentacle_worker.<name> <machine-id>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import [options] octopusdeploy_listening_tentacle_worker.<name> <machine-id>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
resource "octopusdeploy_listening_tentacle_worker" "minimum" {
name = "listening_worker"
machine_policy_id = "machine-policy-1"
worker_pools = ["worker-pools-1", "worker-pools-2"]
thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
uri = "https://tentacle.listening/"
}

resource "octopusdeploy_listening_tentacle_worker" "optionals" {
name = "optional_worker"
machine_policy_id = "machine-policy-1"
worker_pools = ["worker-pools-1"]
thumbprint = "96203ED84246201C26A2F4360D7CBC36AC1D232D"
uri = "https://tentacle.listening/"
proxy_id = "proxys-1"
is_disabled = true
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,5 @@ require (
google.golang.org/protobuf v1.34.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)


1 change: 1 addition & 0 deletions octopusdeploy_framework/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewRunbookResource,
NewTenantResource,
NewTentacleCertificateResource,
NewListeningTentacleWorkerResource,
NewScriptModuleResource,
NewUserResource,
}
Expand Down
4 changes: 2 additions & 2 deletions octopusdeploy_framework/resource_azure_container_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (r *azureContainerRegistryFeedTypeResource) Metadata(ctx context.Context, r
}

func (r *azureContainerRegistryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schemas.GoogleContainerRegistryFeedSchema{}.GetResourceSchema()
resp.Schema = schemas.AzureContainerRegistryFeedSchema{}.GetResourceSchema()
}

func (r *azureContainerRegistryFeedTypeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
Expand Down Expand Up @@ -117,7 +117,7 @@ func (r *azureContainerRegistryFeedTypeResource) Update(ctx context.Context, req

updateAzureDataFromDockerContainerRegistryFeed(data, state.SpaceID.ValueString(), updatedFeed.(*feeds.DockerContainerRegistry))

tflog.Info(ctx, fmt.Sprintf("Google Container Registry feed updated (%s)", data.ID))
tflog.Info(ctx, fmt.Sprintf("Azure Container Registry feed updated (%s)", data.ID))

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
Expand Down
174 changes: 174 additions & 0 deletions octopusdeploy_framework/resource_listening_tentacle_worker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package octopusdeploy_framework

import (
"context"
"fmt"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/workers"
"github.com/hashicorp/terraform-plugin-framework/path"
"net/url"

"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

type listeningTentacleWorkerResource struct {
*Config
}

func NewListeningTentacleWorkerResource() resource.Resource {
return &listeningTentacleWorkerResource{}
}

var _ resource.ResourceWithImportState = &listeningTentacleWorkerResource{}

func (r *listeningTentacleWorkerResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = util.GetTypeName("listening_tentacle_worker")
}

func (r *listeningTentacleWorkerResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schemas.ListeningTentacleWorkerSchema{}.GetResourceSchema()
}

func (r *listeningTentacleWorkerResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
r.Config = ResourceConfiguration(req, resp)
}

func (r *listeningTentacleWorkerResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *schemas.ListeningTentacleWorkerResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

worker := createListeningTentacleWorkerResource(ctx, data)

tflog.Info(ctx, fmt.Sprintf("creating listening tentacle worker: %s", data.Name.ValueString()))

client := r.Config.Client
createdWorker, err := workers.Add(client, worker)
if err != nil {
resp.Diagnostics.AddError("unable to create listening tentacle worker", err.Error())
return
}

updateDataFromListeningTentacleWorker(ctx, data, data.SpaceID.ValueString(), createdWorker)

tflog.Info(ctx, fmt.Sprintf("listening tentacle worker created (%s)", data.ID))
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *listeningTentacleWorkerResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data *schemas.ListeningTentacleWorkerResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Info(ctx, fmt.Sprintf("reading listening tentacle worker (%s)", data.ID))

client := r.Config.Client
worker, err := workers.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "listening tentacle worker"); err != nil {
resp.Diagnostics.AddError("unable to load listening tentacle worker", err.Error())
}
return
}

if worker.Endpoint.GetCommunicationStyle() != "TentaclePassive" {
resp.Diagnostics.AddError("unable to load listening tentacle worker", "found resource is not listening tentacle worker")
return
}

updateDataFromListeningTentacleWorker(ctx, data, data.SpaceID.ValueString(), worker)

tflog.Info(ctx, fmt.Sprintf("listening tentacle worker read (%s)", worker.GetID()))
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *listeningTentacleWorkerResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data, state *schemas.ListeningTentacleWorkerResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Debug(ctx, fmt.Sprintf("updating listening tentacle worker '%s'", data.ID.ValueString()))

worker := createListeningTentacleWorkerResource(ctx, data)
worker.ID = state.ID.ValueString()

tflog.Info(ctx, fmt.Sprintf("updating listening tentacle worker (%s)", data.ID))

client := r.Config.Client
updatedWorker, err := workers.Update(client, worker)
if err != nil {
resp.Diagnostics.AddError("unable to update listening tentacle worker", err.Error())
return
}

updateDataFromListeningTentacleWorker(ctx, data, state.SpaceID.ValueString(), updatedWorker)

tflog.Info(ctx, fmt.Sprintf("listening tentacle worker updated (%s)", data.ID))

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *listeningTentacleWorkerResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data schemas.ListeningTentacleWorkerResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

if err := workers.DeleteByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString()); err != nil {
resp.Diagnostics.AddError("unable to delete listening tentacle worker", err.Error())
return
}
}

func createListeningTentacleWorkerResource(ctx context.Context, data *schemas.ListeningTentacleWorkerResourceModel) *machines.Worker {
uri, _ := url.Parse(data.Uri.ValueString())
endpoint := machines.NewListeningTentacleEndpoint(uri, data.Thumbprint.ValueString())
endpoint.ProxyID = data.ProxyID.ValueString()

worker := machines.NewWorker(data.Name.ValueString(), endpoint)
worker.SpaceID = data.SpaceID.ValueString()
worker.IsDisabled = data.IsDisabled.ValueBool()
worker.MachinePolicyID = data.MachinePolicyID.ValueString()

if !data.WorkerPoolIDs.IsNull() {
var workerPools []string
data.WorkerPoolIDs.ElementsAs(ctx, &workerPools, false)
worker.WorkerPoolIDs = workerPools
}

return worker
}

func updateDataFromListeningTentacleWorker(ctx context.Context, data *schemas.ListeningTentacleWorkerResourceModel, spaceId string, worker *machines.Worker) {
data.ID = types.StringValue(worker.ID)
data.SpaceID = types.StringValue(spaceId)
data.Name = types.StringValue(worker.Name)
data.IsDisabled = types.BoolValue(worker.IsDisabled)
data.MachinePolicyID = types.StringValue(worker.MachinePolicyID)
data.WorkerPoolIDs, _ = types.SetValueFrom(ctx, types.StringType, worker.WorkerPoolIDs)

endpoint := worker.Endpoint.(*machines.ListeningTentacleEndpoint)
data.Uri = types.StringValue(endpoint.URI.String())
data.Thumbprint = types.StringValue(endpoint.Thumbprint)
if endpoint.ProxyID != "" {
data.ProxyID = types.StringValue(endpoint.ProxyID)
}
}

func (*listeningTentacleWorkerResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
Loading

0 comments on commit 8130400

Please sign in to comment.