@@ -2,13 +2,16 @@ package provider
2
2
3
3
import (
4
4
"context"
5
+ "crypto/sha256"
6
+ "encoding/hex"
5
7
"fmt"
6
8
"path/filepath"
7
9
"reflect"
8
10
"strings"
9
11
10
12
".com/google/uuid"
11
13
".com/hashicorp/go-cty/cty"
14
+ ".com/hashicorp/terraform-plugin-log/tflog"
12
15
".com/hashicorp/terraform-plugin-sdk/v2/diag"
13
16
".com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
14
17
".com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -22,10 +25,12 @@ func agentResource() *schema.Resource {
22
25
SchemaVersion : 1 ,
23
26
24
27
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 )
29
34
if err != nil {
30
35
return diag .FromErr (err )
31
36
}
@@ -48,10 +53,12 @@ func agentResource() *schema.Resource {
48
53
return updateInitScript (resourceData , i )
49
54
},
50
55
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 )
52
58
if err != nil {
53
59
return diag .FromErr (err )
54
60
}
61
+
55
62
if _ , ok := resourceData .GetOk ("display_apps" ); ! ok {
56
63
err = resourceData .Set ("display_apps" , []interface {}{
57
64
map [string ]bool {
@@ -469,3 +476,37 @@ func updateInitScript(resourceData *schema.ResourceData, i interface{}) diag.Dia
469
476
}
470
477
return nil
471
478
}
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