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 }