Skip to content
Prev Previous commit
Next Next commit
Add tests for resources
  • Loading branch information
kylecarbs committed Feb 26, 2022
commit 89ca1d7723be9c20197c377c66f0418dcdd76b9c
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
INSTALL_DIR=$(shell go env GOPATH)/bin
GOOS=$(shell go env GOOS)
GOARCH=$(shell go env GOARCH)
Comment on lines +2 to +3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the foundation for cross-compilation coming in 🎉


bin/coder:
mkdir -p bin
go build -o bin/coder cmd/coder/main.go
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o bin/coder-$(GOOS)-$(GOARCH) cmd/coder/main.go
.PHONY: bin/coder

bin/coderd:
Expand Down
8 changes: 2 additions & 6 deletions coderd/provisionerdaemons.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,12 +520,8 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
ID: uuid.New(),
CreatedAt: database.Now(),
WorkspaceHistoryID: input.WorkspaceHistoryID,
InstanceID: sql.NullString{
Valid: protoResource.InstanceId != "",
String: protoResource.InstanceId,
},
Type: protoResource.Type,
Name: protoResource.Name,
Type: protoResource.Type,
Name: protoResource.Name,
// TODO: Generate this at the variable validation phase.
// Set the value in `default_source`, and disallow overwrite.
WorkspaceAgentToken: uuid.NewString(),
Expand Down
5 changes: 2 additions & 3 deletions coderd/workspaceagent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,8 @@ func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) {
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{
Resources: []*proto.Resource{{
Name: "somename",
Type: "someinstance",
InstanceId: instanceID,
Name: "somename",
Type: "someinstance",
}},
},
},
Expand Down
16 changes: 3 additions & 13 deletions provisioner/terraform/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package provider

import (
"context"
"fmt"
"net/url"
"os"
"strings"

"github.com/coder/coder/provisionersdk"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"github.com/coder/coder/provisionersdk"
)

type config struct {
Expand Down Expand Up @@ -62,7 +62,7 @@ func New() *schema.Provider {
archRaw := rd.Get("arch")
arch := archRaw.(string)

script, err := provisionersdk.AgentScript(os, arch, config.URL)
script, err := provisionersdk.AgentScript(config.URL, os, arch)
if err != nil {
return diag.FromErr(err)
}
Expand Down Expand Up @@ -100,16 +100,6 @@ func New() *schema.Provider {
return nil
},
ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
authRaw := rd.Get("auth").([]interface{})[0]
if authRaw != nil {
auth := authRaw.(map[string]interface{})
fmt.Printf("Auth got %+v\n", auth)
}

env := rd.Get("env").(map[string]interface{})
for key, value := range env {
fmt.Printf("Got: %s, %s\n", key, value)
}
return nil
},
DeleteContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
Expand Down
48 changes: 33 additions & 15 deletions provisioner/terraform/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ func TestProvider(t *testing.T) {
require.NoError(t, err)
}

func TestSomething(t *testing.T) {
func TestAgentScript(t *testing.T) {
t.Parallel()
resource.Test(t, resource.TestCase{
Providers: map[string]*schema.Provider{
"coder": provider.New(),
Expand All @@ -34,15 +35,22 @@ func TestSomething(t *testing.T) {
arch = "amd64"
os = "linux"
}`,
Check: func(s *terraform.State) error {
fmt.Printf("check state: %+v\n", s)
Check: func(state *terraform.State) error {
require.Len(t, state.Modules, 1)
require.Len(t, state.Modules[0].Resources, 1)
resource := state.Modules[0].Resources["data.coder_agent_script.new"]
require.NotNil(t, resource)
value := resource.Primary.Attributes["value"]
require.NotNil(t, value)
t.Log(value)
return nil
},
}},
})
}

func TestAnother(t *testing.T) {
func TestAgent(t *testing.T) {
t.Parallel()
resource.Test(t, resource.TestCase{
Providers: map[string]*schema.Provider{
"coder": provider.New(),
Expand All @@ -53,23 +61,33 @@ func TestAnother(t *testing.T) {
provider "coder" {
url = "https://example.com"
}

resource "coder_agent" "new" {
auth {
type = "gcp"
type = "something"
instance_id = "instance"
}
env = {
test = "some magic value"
hi = "test"
}
startup_script = "echo test"
}`,
Check: func(s *terraform.State) error {
fmt.Printf("State: %+v\n", s)
// for _, mod := range s.Modules {
// fmt.Printf("check state: %+v\n", mod.Resources)
// }
// data, _ := json.MarshalIndent(s, "", "\t")
// fmt.Printf("Data: %s\n", data)

Check: func(state *terraform.State) error {
require.Len(t, state.Modules, 1)
require.Len(t, state.Modules[0].Resources, 1)
resource := state.Modules[0].Resources["coder_agent.new"]
require.NotNil(t, resource)
for _, k := range []string{
"token",
"auth.0.type",
"auth.0.instance_id",
"env.hi",
"startup_script",
} {
v := resource.Primary.Attributes[k]
t.Log(fmt.Sprintf("%q = %q", k, v))
require.NotNil(t, v)
require.Greater(t, len(v), 0)
}
return nil
},
}},
Expand Down
13 changes: 2 additions & 11 deletions provisioner/terraform/provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"io"
"os"
"path/filepath"
"reflect"
"strings"

"github.com/hashicorp/terraform-exec/tfexec"
Expand Down Expand Up @@ -246,17 +245,9 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter
resources := make([]*proto.Resource, 0)
if state.Values != nil {
for _, resource := range state.Values.RootModule.Resources {
var instanceID string
if gcpInstanceID, ok := resource.AttributeValues["instance_id"]; ok {
instanceID, ok = gcpInstanceID.(string)
if !ok {
return xerrors.Errorf("invalid type for instance_id property: %s", reflect.TypeOf(gcpInstanceID).String())
}
}
resources = append(resources, &proto.Resource{
Name: resource.Name,
Type: resource.Type,
InstanceId: instanceID,
Name: resource.Name,
Type: resource.Type,
})
}
}
Expand Down
14 changes: 7 additions & 7 deletions provisionersdk/agent.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package provisionersdk

import (
"fmt"
"net/url"
"strings"

Expand Down Expand Up @@ -43,13 +44,9 @@ exec $BINARY_LOCATION agent
}
)

// CODER_URL, operating system, and architecture can return the URL of the Coder binary.

// AgentScript returns an installation script for the specified operating system
// and architecture.
//
// baseURL is
func AgentScript(operatingSystem, architecture string, binaryDownloadURL *url.URL) (string, error) {
func AgentScript(coderURL *url.URL, operatingSystem, architecture string) (string, error) {
architectures, exists := agentScript[operatingSystem]
if !exists {
list := []string{}
Expand All @@ -66,6 +63,9 @@ func AgentScript(operatingSystem, architecture string, binaryDownloadURL *url.UR
}
return "", xerrors.Errorf("architecture %q not supported for %q. must be in: %v", architecture, operatingSystem, list)
}

return strings.ReplaceAll(script, "${DOWNLOAD_URL}", binaryDownloadURL.String()), nil
parsed, err := coderURL.Parse(fmt.Sprintf("/bin/coder-%s-%s", operatingSystem, architecture))
if err != nil {
return "", xerrors.Errorf("parse url: %w", err)
}
return strings.ReplaceAll(script, "${DOWNLOAD_URL}", parsed.String()), nil
}
16 changes: 12 additions & 4 deletions provisionersdk/agent_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
//go:build !windows
// +build !windows

// There isn't a portable Windows binary equivalent to "echo".
// This can be tested, but it's a bit harder.

package provisionersdk_test

import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"os/exec"
"runtime"
Expand All @@ -25,8 +32,9 @@ func TestAgentScript(t *testing.T) {
render.Data(rw, r, content)
}))
t.Cleanup(srv.Close)

script, err := provisionersdk.AgentScript(runtime.GOOS, runtime.GOARCH, srv.URL)
srvURL, err := url.Parse(srv.URL)
require.NoError(t, err)
script, err := provisionersdk.AgentScript(srvURL, runtime.GOOS, runtime.GOARCH)
require.NoError(t, err)

output, err := exec.Command("sh", "-c", script).CombinedOutput()
Expand All @@ -39,13 +47,13 @@ func TestAgentScript(t *testing.T) {

t.Run("UnsupportedOS", func(t *testing.T) {
t.Parallel()
_, err := provisionersdk.AgentScript("unsupported", "", nil)
_, err := provisionersdk.AgentScript(nil, "unsupported", "")
require.Error(t, err)
})

t.Run("UnsupportedArch", func(t *testing.T) {
t.Parallel()
_, err := provisionersdk.AgentScript(runtime.GOOS, "unsupported", nil)
_, err := provisionersdk.AgentScript(nil, runtime.GOOS, "unsupported")
require.Error(t, err)
})
}
83 changes: 46 additions & 37 deletions provisionersdk/proto/provisioner.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions provisionersdk/proto/provisioner.proto
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ message Provision {
string directory = 1;
repeated ParameterValue parameter_values = 2;
bytes state = 3;
bool dry_run = 4;
}
message Complete {
bytes state = 1;
Expand Down