Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add new loadtest type agentconn#4899

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
deansheather merged 2 commits intomainfromdean/loadtest-agentconn
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
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
20 changes: 18 additions & 2 deletionscli/loadtestconfig.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@ import (

"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/loadtest/agentconn"
"github.com/coder/coder/loadtest/harness"
"github.com/coder/coder/loadtest/placebo"
"github.com/coder/coder/loadtest/workspacebuild"
Expand DownExpand Up@@ -86,6 +87,7 @@ func (s LoadTestStrategy) ExecutionStrategy() harness.ExecutionStrategy {
type LoadTestType string

const (
LoadTestTypeAgentConn LoadTestType = "agentconn"
LoadTestTypePlacebo LoadTestType = "placebo"
LoadTestTypeWorkspaceBuild LoadTestType = "workspacebuild"
)
Expand All@@ -97,6 +99,8 @@ type LoadTest struct {
// the count is 0 or negative, defaults to 1.
Count int `json:"count"`

// AgentConn must be set if type == "agentconn".
AgentConn *agentconn.Config `json:"agentconn,omitempty"`
// Placebo must be set if type == "placebo".
Placebo *placebo.Config `json:"placebo,omitempty"`
// WorkspaceBuild must be set if type == "workspacebuild".
Expand All@@ -105,17 +109,20 @@ type LoadTest struct {

func (t LoadTest) NewRunner(client *codersdk.Client) (harness.Runnable, error) {
switch t.Type {
case LoadTestTypeAgentConn:
if t.AgentConn == nil {
return nil, xerrors.New("agentconn config must be set")
}
return agentconn.NewRunner(client, *t.AgentConn), nil
case LoadTestTypePlacebo:
if t.Placebo == nil {
return nil, xerrors.New("placebo config must be set")
}

return placebo.NewRunner(*t.Placebo), nil
case LoadTestTypeWorkspaceBuild:
if t.WorkspaceBuild == nil {
return nil, xerrors.Errorf("workspacebuild config must be set")
}

return workspacebuild.NewRunner(client, *t.WorkspaceBuild), nil
default:
return nil, xerrors.Errorf("unknown test type %q", t.Type)
Expand DownExpand Up@@ -155,6 +162,15 @@ func (s *LoadTestStrategy) Validate() error {

func (t *LoadTest) Validate() error {
switch t.Type {
case LoadTestTypeAgentConn:
if t.AgentConn == nil {
return xerrors.Errorf("agentconn test type must specify agentconn")
}

err := t.AgentConn.Validate()
if err != nil {
return xerrors.Errorf("validate agentconn: %w", err)
}
case LoadTestTypePlacebo:
if t.Placebo == nil {
return xerrors.Errorf("placebo test type must specify placebo")
Expand Down
89 changes: 89 additions & 0 deletionsloadtest/agentconn/config.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
package agentconn

import (
"net/url"

"github.com/google/uuid"
"golang.org/x/xerrors"

"github.com/coder/coder/coderd/httpapi"
)

type ConnectionMode string

const (
ConnectionModeDirect ConnectionMode = "direct"
ConnectionModeDerp ConnectionMode = "derp"
)

type Config struct {
// AgentID is the ID of the agent to connect to.
AgentID uuid.UUID `json:"agent_id"`
// ConnectionMode is the strategy to use when connecting to the agent.
ConnectionMode ConnectionMode `json:"connection_mode"`
// HoldDuration is the duration to hold the connection open for. If set to
// 0, the connection will be closed immediately after making each request
// once.
HoldDuration httpapi.Duration `json:"hold_duration"`

// Connections is the list of connections to make to services running
// inside the workspace. Only HTTP connections are supported.
Connections []Connection `json:"connections"`
}

type Connection struct {
// URL is the address to connect to (e.g. "http://127.0.0.1:8080/path"). The
// endpoint must respond with a any response within timeout. The IP address
// is ignored and the connection is made to the agent's WireGuard IP
// instead.
URL string `json:"url"`
// Interval is the duration to wait between connections to this endpoint. If
// set to 0, the connection will only be made once. Must be set to 0 if
// the parent config's hold_duration is set to 0.
Interval httpapi.Duration `json:"interval"`
// Timeout is the duration to wait for a connection to this endpoint to
// succeed. If set to 0, the default timeout will be used.
Timeout httpapi.Duration `json:"timeout"`
}

func (c Config) Validate() error {
if c.AgentID == uuid.Nil {
return xerrors.New("agent_id must be set")
}
if c.ConnectionMode == "" {
return xerrors.New("connection_mode must be set")
}
switch c.ConnectionMode {
case ConnectionModeDirect:
case ConnectionModeDerp:
default:
return xerrors.Errorf("invalid connection_mode: %q", c.ConnectionMode)
}
if c.HoldDuration < 0 {
return xerrors.New("hold_duration must be a positive value")
}

for i, conn := range c.Connections {
if conn.URL == "" {
return xerrors.Errorf("connections[%d].url must be set", i)
}
u, err := url.Parse(conn.URL)
if err != nil {
return xerrors.Errorf("connections[%d].url is not a valid URL: %w", i, err)
}
if u.Scheme != "http" {
return xerrors.Errorf("connections[%d].url has an unsupported scheme %q, only http is supported", i, u.Scheme)
}
if conn.Interval < 0 {
return xerrors.Errorf("connections[%d].interval must be a positive value", i)
}
if conn.Interval > 0 && c.HoldDuration == 0 {
return xerrors.Errorf("connections[%d].interval must be 0 if hold_duration is 0", i)
}
if conn.Timeout < 0 {
return xerrors.Errorf("connections[%d].timeout must be a positive value", i)
}
}

return nil
}
184 changes: 184 additions & 0 deletionsloadtest/agentconn/config_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
package agentconn_test

import (
"testing"
"time"

"github.com/google/uuid"
"github.com/stretchr/testify/require"

"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/loadtest/agentconn"
)

func Test_Config(t *testing.T) {
t.Parallel()

id := uuid.New()
cases := []struct {
name string
config agentconn.Config
errContains string
}{
{
name: "OK",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: httpapi.Duration(time.Minute),
Connections: []agentconn.Connection{
{
URL: "http://localhost:8080/path",
Interval: httpapi.Duration(time.Second),
Timeout: httpapi.Duration(time.Second),
},
{
URL: "http://localhost:8000/differentpath",
Interval: httpapi.Duration(2 * time.Second),
Timeout: httpapi.Duration(2 * time.Second),
},
},
},
},
{
name: "NoAgentID",
config: agentconn.Config{
AgentID: uuid.Nil,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: 0,
Connections: nil,
},
errContains: "agent_id must be set",
},
{
name: "NoConnectionMode",
config: agentconn.Config{
AgentID: id,
ConnectionMode: "",
HoldDuration: 0,
Connections: nil,
},
errContains: "connection_mode must be set",
},
{
name: "InvalidConnectionMode",
config: agentconn.Config{
AgentID: id,
ConnectionMode: "blah",
HoldDuration: 0,
Connections: nil,
},
errContains: "invalid connection_mode",
},
{
name: "NegativeHoldDuration",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDerp,
HoldDuration: -1,
Connections: nil,
},
errContains: "hold_duration must be a positive value",
},
{
name: "ConnectionNoURL",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: 1,
Connections: []agentconn.Connection{{
URL: "",
Interval: 0,
Timeout: 0,
}},
},
errContains: "connections[0].url must be set",
},
{
name: "ConnectionInvalidURL",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: 1,
Connections: []agentconn.Connection{{
URL: string([]byte{0x7f}),
Interval: 0,
Timeout: 0,
}},
},
errContains: "connections[0].url is not a valid URL",
},
{
name: "ConnectionInvalidURLScheme",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: 1,
Connections: []agentconn.Connection{{
URL: "blah://localhost:8080",
Interval: 0,
Timeout: 0,
}},
},
errContains: "connections[0].url has an unsupported scheme",
},
{
name: "ConnectionNegativeInterval",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: 1,
Connections: []agentconn.Connection{{
URL: "http://localhost:8080",
Interval: -1,
Timeout: 0,
}},
},
errContains: "connections[0].interval must be a positive value",
},
{
name: "ConnectionIntervalMustBeZero",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: 0,
Connections: []agentconn.Connection{{
URL: "http://localhost:8080",
Interval: 1,
Timeout: 0,
}},
},
errContains: "connections[0].interval must be 0 if hold_duration is 0",
},
{
name: "ConnectionNegativeTimeout",
config: agentconn.Config{
AgentID: id,
ConnectionMode: agentconn.ConnectionModeDirect,
HoldDuration: 1,
Connections: []agentconn.Connection{{
URL: "http://localhost:8080",
Interval: 0,
Timeout: -1,
}},
},
errContains: "connections[0].timeout must be a positive value",
},
}

for _, c := range cases {
c := c

t.Run(c.name, func(t *testing.T) {
t.Parallel()

err := c.config.Validate()
if c.errContains != "" {
require.Error(t, err)
require.Contains(t, err.Error(), c.errContains)
} else {
require.NoError(t, err)
}
})
}
}
Loading

[8]ページ先頭

©2009-2025 Movatter.jp