Skip to content

Commit 5648efb

Browse files
SasSwartEmyrk
andauthored
feat: reuse agent tokens when a prebuilt agent reinitializes (#374)
* feat: allow presets to define prebuilds * document prebuild parameters * remove todo * make gen * feat: reuse agent tokens when a prebuilt agent reinitializes * WIP: get agent.go ready to be merged with support for prebuilds * fix: ensure the agent token is reused for prebuilds * lint and make gen * simplify function * test: rbac role test assertion to handle site wide roles Site wide roles have empty string org_ids --------- Co-authored-by: Steven Masley <stevenmasley@gmail.com>
1 parent 4e7da25 commit 5648efb

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/docker/docker v26.1.5+incompatible
77
github.com/google/uuid v1.6.0
88
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
9+
github.com/hashicorp/terraform-plugin-log v0.9.0
910
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1
1011
github.com/masterminds/semver v1.5.0
1112
github.com/mitchellh/mapstructure v1.5.0
@@ -50,7 +51,6 @@ require (
5051
github.com/hashicorp/terraform-exec v0.22.0 // indirect
5152
github.com/hashicorp/terraform-json v0.24.0 // indirect
5253
github.com/hashicorp/terraform-plugin-go v0.26.0 // indirect
53-
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
5454
github.com/hashicorp/terraform-registry-address v0.2.4 // indirect
5555
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
5656
github.com/hashicorp/yamux v0.1.1 // indirect

provider/agent.go

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package provider
22

33
import (
44
"context"
5+
"crypto/sha256"
6+
"encoding/hex"
57
"fmt"
68
"path/filepath"
79
"reflect"
810
"strings"
911

1012
"github.com/google/uuid"
1113
"github.com/hashicorp/go-cty/cty"
14+
"github.com/hashicorp/terraform-plugin-log/tflog"
1215
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1316
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1417
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -22,10 +25,12 @@ func agentResource() *schema.Resource {
2225
SchemaVersion: 1,
2326

2427
Description: "Use this resource to associate an agent.",
25-
CreateContext: func(_ context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
26-
// This should be a real authentication token!
27-
resourceData.SetId(uuid.NewString())
28-
err := resourceData.Set("token", uuid.NewString())
28+
CreateContext: func(ctx context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
29+
agentID := uuid.NewString()
30+
resourceData.SetId(agentID)
31+
32+
token := agentAuthToken(ctx, "")
33+
err := resourceData.Set("token", token)
2934
if err != nil {
3035
return diag.FromErr(err)
3136
}
@@ -48,10 +53,12 @@ func agentResource() *schema.Resource {
4853
return updateInitScript(resourceData, i)
4954
},
5055
ReadWithoutTimeout: func(ctx context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
51-
err := resourceData.Set("token", uuid.NewString())
56+
token := agentAuthToken(ctx, "")
57+
err := resourceData.Set("token", token)
5258
if err != nil {
5359
return diag.FromErr(err)
5460
}
61+
5562
if _, ok := resourceData.GetOk("display_apps"); !ok {
5663
err = resourceData.Set("display_apps", []interface{}{
5764
map[string]bool{
@@ -469,3 +476,37 @@ func updateInitScript(resourceData *schema.ResourceData, i interface{}) diag.Dia
469476
}
470477
return nil
471478
}
479+
480+
func agentAuthToken(ctx context.Context, agentID string) string {
481+
existingToken := helpers.OptionalEnv(RunningAgentTokenEnvironmentVariable(agentID))
482+
if existingToken == "" {
483+
// Most of the time, we will generate a new token for the agent.
484+
// In the case of a prebuilt workspace being claimed, we will override with
485+
// an existing token provided below.
486+
token := uuid.NewString()
487+
return token
488+
}
489+
490+
// An existing token was provided for this agent. That means that this
491+
// is a prebuilt workspace in the process of being claimed.
492+
// We should reuse the token.
493+
tflog.Info(ctx, "using provided agent token for prebuild", map[string]interface{}{
494+
"agent_id": agentID,
495+
})
496+
return existingToken
497+
}
498+
499+
// RunningAgentTokenEnvironmentVariable returns the name of an environment variable
500+
// that contains the token to use for the running agent. This is used for prebuilds,
501+
// where we want to reuse the same token for the next iteration of a workspace agent
502+
// before and after the workspace was claimed by a user.
503+
//
504+
// By reusing an existing token, we can avoid the need to change a value that may have been
505+
// used immutably. Thus, allowing us to avoid reprovisioning resources that may take a long time
506+
// to replace.
507+
//
508+
// agentID is unused for now, but will be used as soon as we support multiple agents.
509+
func RunningAgentTokenEnvironmentVariable(agentID string) string {
510+
sum := sha256.Sum256([]byte(agentID))
511+
return "CODER_RUNNING_WORKSPACE_AGENT_TOKEN_" + hex.EncodeToString(sum[:])
512+
}

provider/workspace.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ func workspaceDataSource() *schema.Resource {
2727
}
2828
_ = rd.Set("start_count", count)
2929

30-
prebuild := helpers.OptionalEnv(IsPrebuildEnvironmentVariable())
31-
prebuildCount := 0
32-
if prebuild == "true" {
33-
prebuildCount = 1
30+
if isPrebuiltWorkspace() {
31+
_ = rd.Set("prebuild_count", 1)
3432
_ = rd.Set("is_prebuild", true)
33+
} else {
34+
_ = rd.Set("prebuild_count", 0)
35+
_ = rd.Set("is_prebuild", false)
3536
}
36-
_ = rd.Set("prebuild_count", prebuildCount)
3737

3838
name := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_NAME", "default")
3939
rd.Set("name", name)
@@ -140,6 +140,24 @@ func workspaceDataSource() *schema.Resource {
140140
}
141141
}
142142

143+
// isPrebuiltWorkspace returns true if the workspace is an unclaimed prebuilt workspace.
144+
func isPrebuiltWorkspace() bool {
145+
return helpers.OptionalEnv(IsPrebuildEnvironmentVariable()) == "true"
146+
}
147+
148+
// IsPrebuildEnvironmentVariable returns the name of the environment variable that
149+
// indicates whether the workspace is an unclaimed prebuilt workspace.
150+
//
151+
// Knowing whether the workspace is an unclaimed prebuilt workspace allows template
152+
// authors to conditionally execute code in the template based on whether the workspace
153+
// has been assigned to a user or not. This allows identity specific configuration to
154+
// be applied only after the workspace is claimed, while the rest of the workspace can
155+
// be pre-configured.
156+
//
157+
// The value of this environment variable should be set to "true" if the workspace is prebuilt
158+
// and it has not yet been claimed by a user. Any other values, including "false"
159+
// and "" will be interpreted to mean that the workspace is not prebuilt, or was
160+
// prebuilt but has since been claimed by a user.
143161
func IsPrebuildEnvironmentVariable() string {
144162
return "CODER_WORKSPACE_IS_PREBUILD"
145163
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy