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

Add support for boundary_self_managed_worker resource. #293

Merged
merged 13 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions docs/resources/worker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "boundary_worker Resource - terraform-provider-boundary"
subcategory: ""
description: |-
The resource allows you to create a self-managed worker object.
---

# boundary_worker (Resource)

The resource allows you to create a self-managed worker object.



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

### Required

- `scope_id` (String) The scope for the worker.

### Optional

- `api_tags` (Map of List of String) API tags applied to the worker.
- `description` (String) The description for the worker.
- `name` (String) The name for the worker.
- `worker_generated_auth_token` (String) The worker authentication token required to register the worker for the worker-led authentication flow. Leaving this blank will result in a controller generated token.

### Read-Only

- `address` (String) The accessible address of the self managed worker.
- `authorized_actions` (List of String) A list of actions that the worker is entitled to perform.
- `canonical_tags` (Map of List of String) The aggregated view of worker tags and API tags.
- `config_tags` (Map of List of String) Tags as configured in the worker's HCL file.
- `controller_generated_activation_token` (String) A single use token generated by the controller to be passed to the self-managed worker.
- `id` (String) The ID of the worker.
- `release_version` (Number) The version of the Boundary binary running on the self managed worker.


1 change: 1 addition & 0 deletions examples/resources/boundary_worker/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import boundary_worker.foo <my-id>
13 changes: 13 additions & 0 deletions examples/resources/boundary_worker/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
resource "boundary_worker" "controller_led" {
scope_id = "global"
name = "worker 1"
description = "self managed worker with controlled led auth"
worker_generated_auth_token = var.worker_generated_auth_token
}

resource "boundary_self_managed_worker" "worker_led" {
scope_id = "global"
name = "worker 2"
description = "self managed worker with controlled led auth"
worker_generated_auth_token = var.worker_generated_auth_token
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func New() *schema.Provider {
"boundary_scope": resourceScope(),
"boundary_target": resourceTarget(),
"boundary_user": resourceUser(),
"boundary_worker": resourceWorker(),
},
}

Expand Down
239 changes: 239 additions & 0 deletions internal/provider/worker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
package provider

import (
"context"
"net/http"

"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/workers"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
scope = "scope"
scopeId = "global"
version = "version"
address = "address"
canonicalTags = "canonical_tags"
configTags = "config_tags"
workerGeneratedAuthToken = "worker_generated_auth_token"
controllerGeneratedActivationToken = "controller_generated_activation_token"
apiTags = "api_tags"
releaseVersion = "release_version"
authorizedActions = "authorized_actions"
)

func resourceWorker() *schema.Resource {
return &schema.Resource{
Description: "The resource allows you to create a self-managed worker object.",

CreateContext: resourceWorkerCreate,
ReadContext: resourceWorkerRead,
UpdateContext: resourceWorkerUpdate,
DeleteContext: resourceWorkerDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
IDKey: {
Description: "The ID of the worker.",
Type: schema.TypeString,
Computed: true,
},
ScopeIdKey: {
Description: "The scope for the worker.",
Type: schema.TypeString,
Required: true,
},
NameKey: {
Description: "The name for the worker.",
Type: schema.TypeString,
Optional: true,
},
DescriptionKey: {
Description: "The description for the worker.",
Type: schema.TypeString,
Optional: true,
},
address: {
Description: "The accessible address of the self managed worker.",
Type: schema.TypeString,
Computed: true,
},
workerGeneratedAuthToken: {
Description: "The worker authentication token required to register the worker for the worker-led authentication flow. Leaving this blank will result in a controller generated token.",
Type: schema.TypeString,
Optional: true,
},
controllerGeneratedActivationToken: {
Description: "A single use token generated by the controller to be passed to the self-managed worker.",
Type: schema.TypeString,
Computed: true,
},
releaseVersion: {
Description: "The version of the Boundary binary running on the self managed worker.",
Type: schema.TypeInt,
Computed: true,
},
authorizedActions: {
Description: "A list of actions that the worker is entitled to perform.",
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Computed: true,
},
},
}
}

func setFromWorkerResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
d.SetId(raw["id"].(string))
d.Set(ScopeIdKey, raw["scope_id"])
d.Set(NameKey, raw["name"])
d.Set(DescriptionKey, raw["description"])
d.Set(address, raw["address"])
d.Set(workerGeneratedAuthToken, raw["worker_generated_auth_token"])
d.Set(controllerGeneratedActivationToken, raw["controller_generated_activation_token"])
d.Set(releaseVersion, raw["release_version"])
d.Set(authorizedActions, raw["authorized_actions"])

return nil
}

func resourceWorkerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
wkrs := workers.NewClient(md.client)

wrr, err := wkrs.Read(ctx, d.Id())
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
d.SetId("")
return nil
}
return diag.Errorf("error calling read worker: %v", err)
}
if wrr == nil {
return diag.Errorf("worker nil after read")
}

if err := setFromWorkerResponseMap(d, wrr.GetResponse().Map); err != nil {
return diag.FromErr(err)
}

return nil
}

func resourceWorkerCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
opts := []workers.Option{}

if v, ok := d.GetOk(NameKey); ok {
opts = append(opts, workers.WithName(v.(string)))
}

if v, ok := d.GetOk(DescriptionKey); ok {
opts = append(opts, workers.WithDescription(v.(string)))
}

var workerAuthToken string
if v, ok := d.GetOk(workerGeneratedAuthToken); ok {
workerAuthToken = v.(string)
}

wkr := workers.NewClient(md.client)

if len(workerAuthToken) > 0 {
wkrc, err := wkr.CreateWorkerLed(ctx, workerAuthToken, scopeId, opts...)
if err != nil {
return diag.Errorf("error creating worker: %v", err)
}
if wkrc == nil {
return diag.Errorf("worker nil after create")
}
if err := setFromWorkerResponseMap(d, wkrc.GetResponse().Map); err != nil {
return diag.FromErr(err)
}
} else {
wkrc, err := wkr.CreateControllerLed(ctx, scopeId, opts...)
if err != nil {
return diag.Errorf("error creating worker: %v", err)
}
if wkrc == nil {
return diag.Errorf("worker nil after create")
}
if err := setFromWorkerResponseMap(d, wkrc.GetResponse().Map); err != nil {
return diag.FromErr(err)
}
}
return nil
}

func resourceWorkerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
wkr := workers.NewClient(md.client)

opts := []workers.Option{}

var name *string
if d.HasChange(NameKey) {
opts = append(opts, workers.DefaultName())
nameVal, ok := d.GetOk(NameKey)
if ok {
nameStr := nameVal.(string)
name = &nameStr
opts = append(opts, workers.WithName(nameStr))
}
}

var desc *string
if d.HasChange(DescriptionKey) {
opts = append(opts, workers.DefaultDescription())
descVal, ok := d.GetOk(DescriptionKey)
if ok {
descStr := descVal.(string)
desc = &descStr
opts = append(opts, workers.WithDescription(descStr))
}
}

var versionInt int
if versionVal, ok := d.GetOk(version); ok {
versionInt = versionVal.(int)
}

if len(opts) > 0 {
opts = append(opts, workers.WithAutomaticVersioning(true))
_, err := wkr.Update(ctx, d.Id(), uint32(versionInt), opts...)
if err != nil {
return diag.Errorf("error updating worker: %v", err)
}
}

if d.HasChange(NameKey) {
if err := d.Set(NameKey, name); err != nil {
return diag.FromErr(err)
}
}
if d.HasChange(DescriptionKey) {
if err := d.Set(DescriptionKey, desc); err != nil {
return diag.FromErr(err)
}
}

return nil
}

func resourceWorkerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
wClient := workers.NewClient(md.client)

_, err := wClient.Delete(ctx, d.Id())
if err != nil {
return diag.Errorf("error deleting worker: %v", err)
}

return nil
}
Loading