@@ -2,13 +2,16 @@ package provider
22
33import (
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+ }
0 commit comments