-
Notifications
You must be signed in to change notification settings - Fork 894
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff 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 | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
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.Must(uuid.NewRandom()) | ||
|
||
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) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.