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

Skip to content

feat: Add API endpoints for the workspace agent #379

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"ntqry",
"oneof",
"parameterscopeid",
"pqtype",
"promptui",
"protobuf",
"provisionerd",
Expand All @@ -61,6 +62,7 @@
"stretchr",
"tcpip",
"tfexec",
"tfjson",
"tfstate",
"unconvert",
"webrtc",
Expand Down
16 changes: 14 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
INSTALL_DIR=$(shell go env GOPATH)/bin
GOOS=$(shell go env GOOS)
GOARCH=$(shell go env GOARCH)

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

bin/coderd:
mkdir -p bin
go build -o bin/coderd cmd/coderd/main.go
.PHONY: bin/coderd

build: site/out bin/coder bin/coderd
bin/terraform-provider-coder:
mkdir -p bin
go build -o bin/terraform-provider-coder cmd/terraform-provider-coder/main.go
.PHONY: bin/terraform-provider-coder

build: site/out bin/coder bin/coderd bin/terraform-provider-coder
.PHONY: build

# Runs migrations to output a dump of the database.
Expand Down Expand Up @@ -59,6 +66,11 @@ install:
@echo "-- CLI available at $(shell ls $(INSTALL_DIR)/coder*)"
.PHONY: install

install/terraform-provider-coder: bin/terraform-provider-coder
$(eval OS_ARCH := $(shell go env GOOS)_$(shell go env GOARCH))
mkdir -p ~/.terraform.d/plugins/coder.com/internal/coder/0.2/$(OS_ARCH)
cp bin/terraform-provider-coder ~/.terraform.d/plugins/coder.com/internal/coder/0.2/$(OS_ARCH)

peerbroker/proto: peerbroker/proto/peerbroker.proto
protoc \
--go_out=. \
Expand Down
9 changes: 9 additions & 0 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"golang.org/x/xerrors"
)

// DialSSH creates an SSH DataChannel on the connection provided.
func DialSSH(conn *peer.Conn) (net.Conn, error) {
channel, err := conn.Dial(context.Background(), "ssh", &peer.ChannelOptions{
Protocol: "ssh",
Expand All @@ -35,6 +36,7 @@ func DialSSH(conn *peer.Conn) (net.Conn, error) {
return channel.NetConn(), nil
}

// DialSSHClient wraps the DialSSH function with a Go SSH client.
func DialSSHClient(conn *peer.Conn) (*gossh.Client, error) {
netConn, err := DialSSH(conn)
if err != nil {
Expand All @@ -59,6 +61,13 @@ type Options struct {
Logger slog.Logger
}

// Dialer to return the peerbroker.Listener, but that hinges on
// a proper authentication token. If it fails to dial for that
// reason, we should check the API error and renegotiate a new
// authentication method.
//
// This also needs to update it's own metadata and such.

type Dialer func(ctx context.Context) (*peerbroker.Listener, error)

func New(dialer Dialer, options *Options) io.Closer {
Expand Down
15 changes: 15 additions & 0 deletions cli/agent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cli

import (
"github.com/spf13/cobra"
)

func agent() *cobra.Command {
return &cobra.Command{
Use: "agent",
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
return nil
},
}
}
19 changes: 8 additions & 11 deletions cli/projectcreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"golang.org/x/xerrors"

"github.com/coder/coder/coderd"
"github.com/coder/coder/coderd/parameter"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/database"
"github.com/coder/coder/provisionerd"
Expand Down Expand Up @@ -72,13 +71,6 @@ func projectCreate() *cobra.Command {
if err != nil {
return err
}
project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
Name: name,
VersionImportJobID: job.ID,
})
if err != nil {
return err
}

_, err = prompt(cmd, &promptui.Prompt{
Label: "Create project?",
Expand All @@ -92,6 +84,14 @@ func projectCreate() *cobra.Command {
return err
}

project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{
Name: name,
VersionImportJobID: job.ID,
})
if err != nil {
return err
}

_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s The %s project has been created!\n", caret, color.HiCyanString(project.Name))
_, err = prompt(cmd, &promptui.Prompt{
Label: "Create a new workspace?",
Expand Down Expand Up @@ -187,9 +187,6 @@ func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, o
if ok {
continue
}
if parameterSchema.Name == parameter.CoderWorkspaceTransition {
continue
}
value, err := prompt(cmd, &promptui.Prompt{
Label: fmt.Sprintf("Enter value for %s:", color.HiCyanString(parameterSchema.Name)),
})
Expand Down
2 changes: 1 addition & 1 deletion cli/projectcreate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestProjectCreate(t *testing.T) {
matches := []string{
"organization?", "y",
"name?", "test-project",
"somevar:", "value",
"somevar", "value",
"project?", "y",
"created!", "n",
}
Expand Down
5 changes: 4 additions & 1 deletion cli/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func projects() *cobra.Command {
return cmd
}

func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProjectImportJobResource) error {
func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProvisionerJobResource) error {
schemaByID := map[string]coderd.ParameterSchema{}
for _, schema := range parameterSchemas {
schemaByID[schema.ID.String()] = schema
Expand Down Expand Up @@ -78,6 +78,9 @@ func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.Para
if resource.Transition == database.WorkspaceTransitionStop {
transition = color.HiRedString("stop")
}
if resource.AgentID != nil {
transition += " with agent"
}
_, _ = fmt.Fprintf(cmd.OutOrStdout(), " %s %s on %s\n\n", color.HiCyanString(resource.Type), color.HiCyanString(resource.Name), transition)
}
return nil
Expand Down
1 change: 1 addition & 0 deletions cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func Root() *cobra.Command {
`Additional help topics:`, header.Sprint("Additional help:"),
).Replace(cmd.UsageTemplate()))

cmd.AddCommand(agent())
cmd.AddCommand(login())
cmd.AddCommand(projects())
cmd.AddCommand(workspaces())
Expand Down
13 changes: 13 additions & 0 deletions cmd/terraform-provider-coder/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"

"github.com/coder/coder/provisioner/terraform/provider"
)

func main() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: provider.New,
})
}
21 changes: 14 additions & 7 deletions coderd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,20 @@ func Root() *cobra.Command {
Use: "coderd",
RunE: func(cmd *cobra.Command, args []string) error {
logger := slog.Make(sloghuman.Sink(os.Stderr))
accessURL := &url.URL{
Scheme: "http",
Host: address,
}
realAccessURL, err := url.Parse("https://v2--kyle.master.cdr.dev/")
if err != nil {
return xerrors.Errorf("parse real access url: %s", err)
}

handler, closeCoderd := coderd.New(&coderd.Options{
Logger: logger,
Database: databasefake.New(),
Pubsub: database.NewPubsubInMemory(),
AccessURL: realAccessURL,
Logger: logger,
Database: databasefake.New(),
Pubsub: database.NewPubsubInMemory(),
})

listener, err := net.Listen("tcp", address)
Expand All @@ -45,10 +55,7 @@ func Root() *cobra.Command {
}
defer listener.Close()

client := codersdk.New(&url.URL{
Scheme: "http",
Host: address,
})
client := codersdk.New(accessURL)
daemonClose, err := newProvisionerDaemon(cmd.Context(), client, logger)
if err != nil {
return xerrors.Errorf("create provisioner daemon: %w", err)
Expand Down
78 changes: 40 additions & 38 deletions coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package coderd

import (
"net/http"
"net/url"
"sync"

"github.com/go-chi/chi/v5"
Expand All @@ -16,9 +17,10 @@ import (

// Options are requires parameters for Coder to start.
type Options struct {
Logger slog.Logger
Database database.Store
Pubsub database.Pubsub
AccessURL *url.URL
Logger slog.Logger
Database database.Store
Pubsub database.Pubsub

GoogleTokenValidator *idtoken.Validator
}
Expand Down Expand Up @@ -58,6 +60,22 @@ func New(options *Options) (http.Handler, func()) {
r.Post("/keys", api.postKeyForUser)
})
})

r.Route("/project/import/{organization}", func(r chi.Router) {
r.Use(
httpmw.ExtractAPIKey(options.Database, nil),
httpmw.ExtractOrganizationParam(options.Database),
)
r.Post("/", api.postProjectImportByOrganization)
r.Route("/{provisionerjob}", func(r chi.Router) {
r.Use(httpmw.ExtractProvisionerJobParam(options.Database))
r.Get("/", api.provisionerJobByID)
r.Get("/schemas", api.projectImportJobSchemasByID)
r.Get("/parameters", api.projectImportJobParametersByID)
r.Get("/resources", api.projectImportJobResourcesByID)
r.Get("/logs", api.provisionerJobLogsByID)
})
})
r.Route("/projects", func(r chi.Router) {
r.Use(
httpmw.ExtractAPIKey(options.Database, nil),
Expand Down Expand Up @@ -87,8 +105,17 @@ func New(options *Options) (http.Handler, func()) {
})
})

// Listing operations specific to resources should go under
// their respective routes. eg. /orgs/<name>/workspaces
r.Route("/workspace/provision/{organization}", func(r chi.Router) {
r.Use(
httpmw.ExtractAPIKey(options.Database, nil),
httpmw.ExtractOrganizationParam(options.Database),
)
r.Route("/{provisionerjob}", func(r chi.Router) {
r.Use(httpmw.ExtractProvisionerJobParam(options.Database))
r.Get("/", api.provisionerJobByID)
r.Get("/logs", api.provisionerJobLogsByID)
})
})
r.Route("/workspaces", func(r chi.Router) {
r.Use(httpmw.ExtractAPIKey(options.Database, nil))
r.Get("/", api.workspaces)
Expand All @@ -98,7 +125,7 @@ func New(options *Options) (http.Handler, func()) {
r.Route("/{workspace}", func(r chi.Router) {
r.Use(httpmw.ExtractWorkspaceParam(options.Database))
r.Get("/", api.workspaceByUser)
r.Route("/version", func(r chi.Router) {
r.Route("/history", func(r chi.Router) {
r.Post("/", api.postWorkspaceHistoryByUser)
r.Get("/", api.workspaceHistoryByUser)
r.Route("/{workspacehistory}", func(r chi.Router) {
Expand All @@ -110,43 +137,18 @@ func New(options *Options) (http.Handler, func()) {
})
})

r.Route("/workspaceagent", func(r chi.Router) {
r.Route("/authenticate", func(r chi.Router) {
r.Post("/google-instance-identity", api.postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity)
r.Route("/agent", func(r chi.Router) {
r.Route("/auth", func(r chi.Router) {
r.Post("/google-instance-identity", api.postAuthWorkspaceAgentUsingGoogleInstanceIdentity)
})
})
r.Route("/{agent}", func(r chi.Router) {

r.Route("/files", func(r chi.Router) {
r.Use(httpmw.ExtractAPIKey(options.Database, nil))
r.Post("/", api.postFiles)
})

r.Route("/projectimport/{organization}", func(r chi.Router) {
r.Use(
httpmw.ExtractAPIKey(options.Database, nil),
httpmw.ExtractOrganizationParam(options.Database),
)
r.Post("/", api.postProjectImportByOrganization)
r.Route("/{provisionerjob}", func(r chi.Router) {
r.Use(httpmw.ExtractProvisionerJobParam(options.Database))
r.Get("/", api.provisionerJobByID)
r.Get("/schemas", api.projectImportJobSchemasByID)
r.Get("/parameters", api.projectImportJobParametersByID)
r.Get("/resources", api.projectImportJobResourcesByID)
r.Get("/logs", api.provisionerJobLogsByID)
})
})

r.Route("/workspaceprovision/{organization}", func(r chi.Router) {
r.Use(
httpmw.ExtractAPIKey(options.Database, nil),
httpmw.ExtractOrganizationParam(options.Database),
)
r.Route("/{provisionerjob}", func(r chi.Router) {
r.Use(httpmw.ExtractProvisionerJobParam(options.Database))
r.Get("/", api.provisionerJobByID)
r.Get("/logs", api.provisionerJobLogsByID)
})
r.Route("/upload", func(r chi.Router) {
r.Use(httpmw.ExtractAPIKey(options.Database, nil))
r.Post("/", api.postUpload)
})

r.Route("/provisioners/daemons", func(r chi.Router) {
Expand Down
19 changes: 11 additions & 8 deletions coderd/coderdtest/coderdtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,7 @@ func New(t *testing.T, options *Options) *codersdk.Client {
})
}

handler, closeWait := coderd.New(&coderd.Options{
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
Database: db,
Pubsub: pubsub,

GoogleTokenValidator: options.GoogleTokenValidator,
})
srv := httptest.NewUnstartedServer(handler)
srv := httptest.NewUnstartedServer(nil)
srv.Config.BaseContext = func(_ net.Listener) context.Context {
ctx, cancelFunc := context.WithCancel(context.Background())
t.Cleanup(cancelFunc)
Expand All @@ -96,6 +89,16 @@ func New(t *testing.T, options *Options) *codersdk.Client {
srv.Start()
serverURL, err := url.Parse(srv.URL)
require.NoError(t, err)
var closeWait func()
// We set the handler after server creation for the access URL.
srv.Config.Handler, closeWait = coderd.New(&coderd.Options{
AccessURL: serverURL,
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
Database: db,
Pubsub: pubsub,

GoogleTokenValidator: options.GoogleTokenValidator,
})
t.Cleanup(func() {
srv.Close()
closeWait()
Expand Down
2 changes: 1 addition & 1 deletion coderd/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type UploadFileResponse struct {
Hash string `json:"hash"`
}

func (api *api) postFiles(rw http.ResponseWriter, r *http.Request) {
func (api *api) postUpload(rw http.ResponseWriter, r *http.Request) {
apiKey := httpmw.APIKey(r)
contentType := r.Header.Get("Content-Type")

Expand Down
Loading