Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a06821c

Browse files
authored
feat: Update Coder Terraform Provider to v0.2.1 (#563)
This update exposes the workspace name and owner, and changes authentication methods to be explicit. Implicit authentication added unnecessary complexity and introduced inconsistency.
1 parent 27c24de commit a06821c

File tree

10 files changed

+233
-230
lines changed

10 files changed

+233
-230
lines changed

cli/workspaceagent.go

+34-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package cli
22

33
import (
4+
"context"
45
"net/url"
56
"os"
7+
"time"
68

79
"github.com/spf13/cobra"
810
"golang.org/x/xerrors"
@@ -13,13 +15,13 @@ import (
1315
"github.com/coder/coder/agent"
1416
"github.com/coder/coder/codersdk"
1517
"github.com/coder/coder/peer"
18+
"github.com/coder/retry"
1619
)
1720

1821
func workspaceAgent() *cobra.Command {
1922
return &cobra.Command{
2023
Use: "agent",
21-
// This command isn't useful for users, and seems
22-
// more likely to confuse.
24+
// This command isn't useful to manually execute.
2325
Hidden: true,
2426
RunE: func(cmd *cobra.Command, args []string) error {
2527
coderURLRaw, exists := os.LookupEnv("CODER_URL")
@@ -30,30 +32,42 @@ func workspaceAgent() *cobra.Command {
3032
if err != nil {
3133
return xerrors.Errorf("parse %q: %w", coderURLRaw, err)
3234
}
35+
logger := slog.Make(sloghuman.Sink(cmd.OutOrStdout()))
3336
client := codersdk.New(coderURL)
34-
sessionToken, exists := os.LookupEnv("CODER_TOKEN")
37+
auth, exists := os.LookupEnv("CODER_AUTH")
3538
if !exists {
36-
// probe, err := cloud.New()
37-
// if err != nil {
38-
// return xerrors.Errorf("probe cloud: %w", err)
39-
// }
40-
// if !probe.Detected {
41-
// return xerrors.Errorf("no valid authentication method found; set \"CODER_TOKEN\"")
42-
// }
43-
// switch {
44-
// case probe.GCP():
45-
response, err := client.AuthWorkspaceGoogleInstanceIdentity(cmd.Context(), "", nil)
39+
auth = "token"
40+
}
41+
switch auth {
42+
case "token":
43+
sessionToken, exists := os.LookupEnv("CODER_TOKEN")
44+
if !exists {
45+
return xerrors.Errorf("CODER_TOKEN must be set for token auth")
46+
}
47+
client.SessionToken = sessionToken
48+
case "google-instance-identity":
49+
ctx, cancelFunc := context.WithTimeout(cmd.Context(), 30*time.Second)
50+
defer cancelFunc()
51+
for retry.New(100*time.Millisecond, 5*time.Second).Wait(ctx) {
52+
var response codersdk.WorkspaceAgentAuthenticateResponse
53+
response, err = client.AuthWorkspaceGoogleInstanceIdentity(cmd.Context(), "", nil)
54+
if err != nil {
55+
logger.Warn(ctx, "authenticate workspace with Google Instance Identity", slog.Error(err))
56+
continue
57+
}
58+
client.SessionToken = response.SessionToken
59+
break
60+
}
4661
if err != nil {
47-
return xerrors.Errorf("authenticate workspace with gcp: %w", err)
62+
return xerrors.Errorf("agent failed to authenticate in time: %w", err)
4863
}
49-
sessionToken = response.SessionToken
50-
// default:
51-
// return xerrors.Errorf("%q authentication not supported; set \"CODER_TOKEN\" instead", probe.Name)
52-
// }
64+
case "aws-instance-identity":
65+
return xerrors.Errorf("not implemented")
66+
case "azure-instance-identity":
67+
return xerrors.Errorf("not implemented")
5368
}
54-
client.SessionToken = sessionToken
5569
closer := agent.New(client.ListenWorkspaceAgent, &peer.ConnOptions{
56-
Logger: slog.Make(sloghuman.Sink(cmd.OutOrStdout())),
70+
Logger: logger,
5771
})
5872
<-cmd.Context().Done()
5973
return closer.Close()

coderd/provisionerdaemons.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
183183
if err != nil {
184184
return nil, failJob(fmt.Sprintf("get project: %s", err))
185185
}
186+
owner, err := server.Database.GetUserByID(ctx, workspace.OwnerID)
187+
if err != nil {
188+
return nil, failJob(fmt.Sprintf("get owner: %s", err))
189+
}
186190

187191
// Compute parameters for the workspace to consume.
188192
parameters, err := parameter.Compute(ctx, server.Database, parameter.ComputeScope{
@@ -224,6 +228,8 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty
224228
Metadata: &sdkproto.Provision_Metadata{
225229
CoderUrl: server.AccessURL.String(),
226230
WorkspaceTransition: transition,
231+
WorkspaceName: workspace.Name,
232+
WorkspaceOwner: owner.Username,
227233
},
228234
},
229235
}
@@ -591,9 +597,9 @@ func insertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
591597
}
592598
if resource.AgentID.Valid {
593599
var instanceID sql.NullString
594-
if protoResource.Agent.GetGoogleInstanceIdentity() != nil {
600+
if protoResource.Agent.GetInstanceId() != "" {
595601
instanceID = sql.NullString{
596-
String: protoResource.Agent.GetGoogleInstanceIdentity().InstanceId,
602+
String: protoResource.Agent.GetInstanceId(),
597603
Valid: true,
598604
}
599605
}

coderd/workspaceresourceauth_test.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ func TestPostWorkspaceAuthGoogleInstanceIdentity(t *testing.T) {
7575
Name: "somename",
7676
Type: "someinstance",
7777
Agent: &proto.Agent{
78-
Auth: &proto.Agent_GoogleInstanceIdentity{
79-
GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{},
78+
Auth: &proto.Agent_InstanceId{
79+
InstanceId: "",
8080
},
8181
},
8282
}},
@@ -90,10 +90,8 @@ func TestPostWorkspaceAuthGoogleInstanceIdentity(t *testing.T) {
9090
Name: "somename",
9191
Type: "someinstance",
9292
Agent: &proto.Agent{
93-
Auth: &proto.Agent_GoogleInstanceIdentity{
94-
GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{
95-
InstanceId: instanceID,
96-
},
93+
Auth: &proto.Agent_InstanceId{
94+
InstanceId: instanceID,
9795
},
9896
},
9997
}},

examples/gcp-linux/main.tf

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ terraform {
22
required_providers {
33
coder = {
44
source = "coder/coder"
5+
version = "0.2.1"
56
}
67
}
78
}
@@ -41,6 +42,7 @@ data "coder_workspace" "me" {
4142
}
4243

4344
data "coder_agent_script" "dev" {
45+
auth = "google-instance-identity"
4446
arch = "amd64"
4547
os = "linux"
4648
}
@@ -87,8 +89,5 @@ resource "google_compute_instance" "dev" {
8789

8890
resource "coder_agent" "dev" {
8991
count = length(google_compute_instance.dev)
90-
auth {
91-
type = "google-instance-identity"
92-
instance_id = google_compute_instance.dev[0].instance_id
93-
}
92+
instance_id = google_compute_instance.dev[0].instance_id
9493
}

provisioner/terraform/provision.go

+23-49
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"os"
1010
"os/exec"
1111
"path/filepath"
12-
"reflect"
1312
"strings"
1413

1514
"github.com/hashicorp/terraform-exec/tfexec"
@@ -102,6 +101,8 @@ func (t *terraform) Provision(stream proto.DRPCProvisioner_ProvisionStream) erro
102101
env = append(env,
103102
"CODER_URL="+start.Metadata.CoderUrl,
104103
"CODER_WORKSPACE_TRANSITION="+strings.ToLower(start.Metadata.WorkspaceTransition.String()),
104+
"CODER_WORKSPACE_NAME="+start.Metadata.WorkspaceName,
105+
"CODER_WORKSPACE_OWNER="+start.Metadata.WorkspaceOwner,
105106
)
106107
for key, value := range provisionersdk.AgentScriptEnv() {
107108
env = append(env, key+"="+value)
@@ -285,38 +286,24 @@ func parseTerraformPlan(ctx context.Context, terraform *tfexec.Terraform, planfi
285286
if envRaw, has := resource.Expressions["env"]; has {
286287
env, ok := envRaw.ConstantValue.(map[string]string)
287288
if !ok {
288-
return nil, xerrors.Errorf("unexpected type %q for env map", reflect.TypeOf(envRaw.ConstantValue).String())
289+
return nil, xerrors.Errorf("unexpected type %T for env map", envRaw.ConstantValue)
289290
}
290291
agent.Env = env
291292
}
292293
if startupScriptRaw, has := resource.Expressions["startup_script"]; has {
293294
startupScript, ok := startupScriptRaw.ConstantValue.(string)
294295
if !ok {
295-
return nil, xerrors.Errorf("unexpected type %q for startup script", reflect.TypeOf(startupScriptRaw.ConstantValue).String())
296+
return nil, xerrors.Errorf("unexpected type %T for startup script", startupScriptRaw.ConstantValue)
296297
}
297298
agent.StartupScript = startupScript
298299
}
299-
if auth, has := resource.Expressions["auth"]; has {
300-
if len(auth.ExpressionData.NestedBlocks) > 0 {
301-
block := auth.ExpressionData.NestedBlocks[0]
302-
authType, has := block["type"]
303-
if has {
304-
authTypeValue, valid := authType.ConstantValue.(string)
305-
if !valid {
306-
return nil, xerrors.Errorf("unexpected type %q for auth type", reflect.TypeOf(authType.ConstantValue))
307-
}
308-
switch authTypeValue {
309-
case "google-instance-identity":
310-
instanceID, _ := block["instance_id"].ConstantValue.(string)
311-
agent.Auth = &proto.Agent_GoogleInstanceIdentity{
312-
GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{
313-
InstanceId: instanceID,
314-
},
315-
}
316-
default:
317-
return nil, xerrors.Errorf("unknown auth type: %q", authTypeValue)
318-
}
319-
}
300+
if instanceIDRaw, has := resource.Expressions["instance_id"]; has {
301+
instanceID, ok := instanceIDRaw.ConstantValue.(string)
302+
if !ok {
303+
return nil, xerrors.Errorf("unexpected type %T for instance_id", instanceIDRaw.ConstantValue)
304+
}
305+
agent.Auth = &proto.Agent_InstanceId{
306+
InstanceId: instanceID,
320307
}
321308
}
322309

@@ -379,12 +366,9 @@ func parseTerraformApply(ctx context.Context, terraform *tfexec.Terraform, state
379366
resources := make([]*proto.Resource, 0)
380367
if state.Values != nil {
381368
type agentAttributes struct {
382-
ID string `mapstructure:"id"`
383-
Token string `mapstructure:"token"`
384-
Auth []struct {
385-
Type string `mapstructure:"type"`
386-
InstanceID string `mapstructure:"instance_id"`
387-
} `mapstructure:"auth"`
369+
ID string `mapstructure:"id"`
370+
Token string `mapstructure:"token"`
371+
InstanceID string `mapstructure:"instance_id"`
388372
Env map[string]string `mapstructure:"env"`
389373
StartupScript string `mapstructure:"startup_script"`
390374
}
@@ -409,17 +393,9 @@ func parseTerraformApply(ctx context.Context, terraform *tfexec.Terraform, state
409393
Token: attrs.Token,
410394
},
411395
}
412-
if len(attrs.Auth) > 0 {
413-
auth := attrs.Auth[0]
414-
switch auth.Type {
415-
case "google-instance-identity":
416-
agent.Auth = &proto.Agent_GoogleInstanceIdentity{
417-
GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{
418-
InstanceId: auth.InstanceID,
419-
},
420-
}
421-
default:
422-
return nil, xerrors.Errorf("unknown auth type: %q", auth.Type)
396+
if attrs.InstanceID != "" {
397+
agent.Auth = &proto.Agent_InstanceId{
398+
InstanceId: attrs.InstanceID,
423399
}
424400
}
425401
resourceKey := strings.Join([]string{resource.Type, resource.Name}, ".")
@@ -453,14 +429,12 @@ func parseTerraformApply(ctx context.Context, terraform *tfexec.Terraform, state
453429
}
454430
}
455431

456-
if agent != nil {
457-
if agent.GetGoogleInstanceIdentity() != nil {
458-
// Make sure the instance has an instance ID!
459-
_, exists := resource.AttributeValues["instance_id"]
460-
if !exists {
461-
// This was a mistake!
462-
agent = nil
463-
}
432+
if agent != nil && agent.GetInstanceId() != "" {
433+
// Make sure the instance has an instance ID!
434+
_, exists := resource.AttributeValues["instance_id"]
435+
if !exists {
436+
// This was a mistake!
437+
agent = nil
464438
}
465439
}
466440

provisioner/terraform/provision_test.go

+5-13
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ terraform {
2727
required_providers {
2828
coder = {
2929
source = "coder/coder"
30-
version = "0.1.0"
30+
version = "0.2.1"
3131
}
3232
}
3333
}
@@ -195,10 +195,7 @@ provider "coder" {
195195
depends_on = [
196196
null_resource.A
197197
]
198-
auth {
199-
type = "google-instance-identity"
200-
instance_id = "an-instance"
201-
}
198+
instance_id = "an-instance"
202199
}
203200
resource "null_resource" "A" {}`,
204201
},
@@ -261,10 +258,7 @@ provider "coder" {
261258
"main.tf": provider + `
262259
resource "coder_agent" "A" {
263260
count = length(null_resource.A)
264-
auth {
265-
type = "google-instance-identity"
266-
instance_id = "an-instance"
267-
}
261+
instance_id = "an-instance"
268262
}
269263
resource "null_resource" "A" {
270264
count = 1
@@ -287,10 +281,8 @@ provider "coder" {
287281
Name: "A",
288282
Type: "null_resource",
289283
Agent: &proto.Agent{
290-
Auth: &proto.Agent_GoogleInstanceIdentity{
291-
GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{
292-
InstanceId: "an-instance",
293-
},
284+
Auth: &proto.Agent_InstanceId{
285+
InstanceId: "an-instance",
294286
},
295287
},
296288
}},

provisionersdk/agent.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var (
1111
"amd64": `
1212
$ProgressPreference = "SilentlyContinue"
1313
Invoke-WebRequest -Uri ${ACCESS_URL}bin/coder-windows-amd64.exe -OutFile $env:TEMP\coder.exe
14+
$env:CODER_AUTH = "${AUTH_TYPE}"
1415
$env:CODER_URL = "${ACCESS_URL}"
1516
Start-Process -FilePath $env:TEMP\coder.exe -ArgumentList "workspaces","agent" -PassThru
1617
`,
@@ -19,9 +20,10 @@ Start-Process -FilePath $env:TEMP\coder.exe -ArgumentList "workspaces","agent" -
1920
"amd64": `
2021
#!/usr/bin/env sh
2122
set -eu pipefail
22-
BINARY_LOCATION=$(mktemp -d)/coder
23+
export BINARY_LOCATION=$(mktemp -d)/coder
2324
curl -fsSL ${ACCESS_URL}bin/coder-linux-amd64 -o $BINARY_LOCATION
2425
chmod +x $BINARY_LOCATION
26+
export CODER_AUTH="${AUTH_TYPE}"
2527
export CODER_URL="${ACCESS_URL}"
2628
exec $BINARY_LOCATION workspaces agent
2729
`,
@@ -30,9 +32,10 @@ exec $BINARY_LOCATION workspaces agent
3032
"amd64": `
3133
#!/usr/bin/env sh
3234
set -eu pipefail
33-
BINARY_LOCATION=$(mktemp -d)/coder
35+
export BINARY_LOCATION=$(mktemp -d)/coder
3436
curl -fsSL ${ACCESS_URL}bin/coder-darwin-amd64 -o $BINARY_LOCATION
3537
chmod +x $BINARY_LOCATION
38+
export CODER_AUTH="${AUTH_TYPE}"
3639
export CODER_URL="${ACCESS_URL}"
3740
exec $BINARY_LOCATION workspaces agent
3841
`,

provisionersdk/agent_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func TestAgentScript(t *testing.T) {
4545
return
4646
}
4747
script = strings.ReplaceAll(script, "${ACCESS_URL}", srvURL.String()+"/")
48+
script = strings.ReplaceAll(script, "${AUTH_TYPE}", "token")
4849
output, err := exec.Command("sh", "-c", script).CombinedOutput()
4950
t.Log(string(output))
5051
require.NoError(t, err)

0 commit comments

Comments
 (0)