diff --git a/CLAUDE.md b/CLAUDE.md index e587796..046bb2d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -65,6 +65,7 @@ func FunctionName( - Suite naming: `*_public_test.go` → `{Name}PublicTestSuite`, `*_test.go` → `{Name}TestSuite` - Use `testify/suite` with table-driven patterns +- One suite method per function under test — all scenarios (success, errors, edge cases) as rows in one table ### Go Patterns diff --git a/docs/development.md b/docs/development.md index 339e979..cb37209 100644 --- a/docs/development.md +++ b/docs/development.md @@ -65,6 +65,10 @@ go test -run TestName -v ./pkg/osapi/... # Run a single test exported functions. - Use `testify/suite` with table-driven patterns. - Table-driven structure with `validateFunc` callbacks. +- **One suite method per function under test.** All scenarios for a function + (success, error codes, transport failures, nil responses) belong as rows in a + single table — never split into separate `TestFoo`, `TestFooError`, + `TestFooNilResponse` methods. ## Branching diff --git a/docs/gen/gen.md b/docs/gen/gen.md index aa7d121..a8bec70 100644 --- a/docs/gen/gen.md +++ b/docs/gen/gen.md @@ -16,6 +16,7 @@ Package gen contains generated code for the OSAPI REST API client. - [Constants](<#constants>) - [func NewDeleteJobByIDRequest\(server string, id openapi\_types.UUID\) \(\*http.Request, error\)](<#NewDeleteJobByIDRequest>) +- [func NewDrainAgentRequest\(server string, hostname string\) \(\*http.Request, error\)](<#NewDrainAgentRequest>) - [func NewGetAgentDetailsRequest\(server string, hostname string\) \(\*http.Request, error\)](<#NewGetAgentDetailsRequest>) - [func NewGetAgentRequest\(server string\) \(\*http.Request, error\)](<#NewGetAgentRequest>) - [func NewGetAuditExportRequest\(server string\) \(\*http.Request, error\)](<#NewGetAuditExportRequest>) @@ -48,8 +49,10 @@ Package gen contains generated code for the OSAPI REST API client. - [func NewPutNodeNetworkDNSRequestWithBody\(server string, hostname Hostname, contentType string, body io.Reader\) \(\*http.Request, error\)](<#NewPutNodeNetworkDNSRequestWithBody>) - [func NewRetryJobByIDRequest\(server string, id openapi\_types.UUID, body RetryJobByIDJSONRequestBody\) \(\*http.Request, error\)](<#NewRetryJobByIDRequest>) - [func NewRetryJobByIDRequestWithBody\(server string, id openapi\_types.UUID, contentType string, body io.Reader\) \(\*http.Request, error\)](<#NewRetryJobByIDRequestWithBody>) +- [func NewUndrainAgentRequest\(server string, hostname string\) \(\*http.Request, error\)](<#NewUndrainAgentRequest>) - [type AgentDetail](<#AgentDetail>) - [type AgentInfo](<#AgentInfo>) +- [type AgentInfoState](<#AgentInfoState>) - [type AgentInfoStatus](<#AgentInfoStatus>) - [type AgentStats](<#AgentStats>) - [type AuditEntry](<#AuditEntry>) @@ -57,6 +60,7 @@ Package gen contains generated code for the OSAPI REST API client. - [type Client](<#Client>) - [func NewClient\(server string, opts ...ClientOption\) \(\*Client, error\)](<#NewClient>) - [func \(c \*Client\) DeleteJobByID\(ctx context.Context, id openapi\_types.UUID, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.DeleteJobByID>) + - [func \(c \*Client\) DrainAgent\(ctx context.Context, hostname string, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.DrainAgent>) - [func \(c \*Client\) GetAgent\(ctx context.Context, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.GetAgent>) - [func \(c \*Client\) GetAgentDetails\(ctx context.Context, hostname string, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.GetAgentDetails>) - [func \(c \*Client\) GetAuditExport\(ctx context.Context, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.GetAuditExport>) @@ -89,6 +93,7 @@ Package gen contains generated code for the OSAPI REST API client. - [func \(c \*Client\) PutNodeNetworkDNSWithBody\(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.PutNodeNetworkDNSWithBody>) - [func \(c \*Client\) RetryJobByID\(ctx context.Context, id openapi\_types.UUID, body RetryJobByIDJSONRequestBody, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.RetryJobByID>) - [func \(c \*Client\) RetryJobByIDWithBody\(ctx context.Context, id openapi\_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.RetryJobByIDWithBody>) + - [func \(c \*Client\) UndrainAgent\(ctx context.Context, hostname string, reqEditors ...RequestEditorFn\) \(\*http.Response, error\)](<#Client.UndrainAgent>) - [type ClientInterface](<#ClientInterface>) - [type ClientOption](<#ClientOption>) - [func WithBaseURL\(baseURL string\) ClientOption](<#WithBaseURL>) @@ -97,6 +102,7 @@ Package gen contains generated code for the OSAPI REST API client. - [type ClientWithResponses](<#ClientWithResponses>) - [func NewClientWithResponses\(server string, opts ...ClientOption\) \(\*ClientWithResponses, error\)](<#NewClientWithResponses>) - [func \(c \*ClientWithResponses\) DeleteJobByIDWithResponse\(ctx context.Context, id openapi\_types.UUID, reqEditors ...RequestEditorFn\) \(\*DeleteJobByIDResponse, error\)](<#ClientWithResponses.DeleteJobByIDWithResponse>) + - [func \(c \*ClientWithResponses\) DrainAgentWithResponse\(ctx context.Context, hostname string, reqEditors ...RequestEditorFn\) \(\*DrainAgentResponse, error\)](<#ClientWithResponses.DrainAgentWithResponse>) - [func \(c \*ClientWithResponses\) GetAgentDetailsWithResponse\(ctx context.Context, hostname string, reqEditors ...RequestEditorFn\) \(\*GetAgentDetailsResponse, error\)](<#ClientWithResponses.GetAgentDetailsWithResponse>) - [func \(c \*ClientWithResponses\) GetAgentWithResponse\(ctx context.Context, reqEditors ...RequestEditorFn\) \(\*GetAgentResponse, error\)](<#ClientWithResponses.GetAgentWithResponse>) - [func \(c \*ClientWithResponses\) GetAuditExportWithResponse\(ctx context.Context, reqEditors ...RequestEditorFn\) \(\*GetAuditExportResponse, error\)](<#ClientWithResponses.GetAuditExportWithResponse>) @@ -129,6 +135,7 @@ Package gen contains generated code for the OSAPI REST API client. - [func \(c \*ClientWithResponses\) PutNodeNetworkDNSWithResponse\(ctx context.Context, hostname Hostname, body PutNodeNetworkDNSJSONRequestBody, reqEditors ...RequestEditorFn\) \(\*PutNodeNetworkDNSResponse, error\)](<#ClientWithResponses.PutNodeNetworkDNSWithResponse>) - [func \(c \*ClientWithResponses\) RetryJobByIDWithBodyWithResponse\(ctx context.Context, id openapi\_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn\) \(\*RetryJobByIDResponse, error\)](<#ClientWithResponses.RetryJobByIDWithBodyWithResponse>) - [func \(c \*ClientWithResponses\) RetryJobByIDWithResponse\(ctx context.Context, id openapi\_types.UUID, body RetryJobByIDJSONRequestBody, reqEditors ...RequestEditorFn\) \(\*RetryJobByIDResponse, error\)](<#ClientWithResponses.RetryJobByIDWithResponse>) + - [func \(c \*ClientWithResponses\) UndrainAgentWithResponse\(ctx context.Context, hostname string, reqEditors ...RequestEditorFn\) \(\*UndrainAgentResponse, error\)](<#ClientWithResponses.UndrainAgentWithResponse>) - [type ClientWithResponsesInterface](<#ClientWithResponsesInterface>) - [type CommandExecRequest](<#CommandExecRequest>) - [type CommandResultCollectionResponse](<#CommandResultCollectionResponse>) @@ -153,6 +160,10 @@ Package gen contains generated code for the OSAPI REST API client. - [type DiskResponse](<#DiskResponse>) - [type DiskResultItem](<#DiskResultItem>) - [type DisksResponse](<#DisksResponse>) +- [type DrainAgentResponse](<#DrainAgentResponse>) + - [func ParseDrainAgentResponse\(rsp \*http.Response\) \(\*DrainAgentResponse, error\)](<#ParseDrainAgentResponse>) + - [func \(r DrainAgentResponse\) Status\(\) string](<#DrainAgentResponse.Status>) + - [func \(r DrainAgentResponse\) StatusCode\(\) int](<#DrainAgentResponse.StatusCode>) - [type ErrorResponse](<#ErrorResponse>) - [type GetAgentDetailsResponse](<#GetAgentDetailsResponse>) - [func ParseGetAgentDetailsResponse\(rsp \*http.Response\) \(\*GetAgentDetailsResponse, error\)](<#ParseGetAgentDetailsResponse>) @@ -257,6 +268,8 @@ Package gen contains generated code for the OSAPI REST API client. - [type NATSInfo](<#NATSInfo>) - [type NetworkInterfaceResponse](<#NetworkInterfaceResponse>) - [type NetworkInterfaceResponseFamily](<#NetworkInterfaceResponseFamily>) +- [type NodeCondition](<#NodeCondition>) +- [type NodeConditionType](<#NodeConditionType>) - [type NodeStatusCollectionResponse](<#NodeStatusCollectionResponse>) - [type NodeStatusResponse](<#NodeStatusResponse>) - [type OSInfoCollectionResponse](<#OSInfoCollectionResponse>) @@ -301,6 +314,11 @@ Package gen contains generated code for the OSAPI REST API client. - [type RetryJobRequest](<#RetryJobRequest>) - [type StatusResponse](<#StatusResponse>) - [type StreamInfo](<#StreamInfo>) +- [type TimelineEvent](<#TimelineEvent>) +- [type UndrainAgentResponse](<#UndrainAgentResponse>) + - [func ParseUndrainAgentResponse\(rsp \*http.Response\) \(\*UndrainAgentResponse, error\)](<#ParseUndrainAgentResponse>) + - [func \(r UndrainAgentResponse\) Status\(\) string](<#UndrainAgentResponse.Status>) + - [func \(r UndrainAgentResponse\) StatusCode\(\) int](<#UndrainAgentResponse.StatusCode>) - [type UptimeCollectionResponse](<#UptimeCollectionResponse>) - [type UptimeResponse](<#UptimeResponse>) @@ -316,7 +334,7 @@ const ( ``` -## func [NewDeleteJobByIDRequest]() +## func [NewDeleteJobByIDRequest]() ```go func NewDeleteJobByIDRequest(server string, id openapi_types.UUID) (*http.Request, error) @@ -324,8 +342,17 @@ func NewDeleteJobByIDRequest(server string, id openapi_types.UUID) (*http.Reques NewDeleteJobByIDRequest generates requests for DeleteJobByID + +## func [NewDrainAgentRequest]() + +```go +func NewDrainAgentRequest(server string, hostname string) (*http.Request, error) +``` + +NewDrainAgentRequest generates requests for DrainAgent + -## func [NewGetAgentDetailsRequest]() +## func [NewGetAgentDetailsRequest]() ```go func NewGetAgentDetailsRequest(server string, hostname string) (*http.Request, error) @@ -334,7 +361,7 @@ func NewGetAgentDetailsRequest(server string, hostname string) (*http.Request, e NewGetAgentDetailsRequest generates requests for GetAgentDetails -## func [NewGetAgentRequest]() +## func [NewGetAgentRequest]() ```go func NewGetAgentRequest(server string) (*http.Request, error) @@ -343,7 +370,7 @@ func NewGetAgentRequest(server string) (*http.Request, error) NewGetAgentRequest generates requests for GetAgent -## func [NewGetAuditExportRequest]() +## func [NewGetAuditExportRequest]() ```go func NewGetAuditExportRequest(server string) (*http.Request, error) @@ -352,7 +379,7 @@ func NewGetAuditExportRequest(server string) (*http.Request, error) NewGetAuditExportRequest generates requests for GetAuditExport -## func [NewGetAuditLogByIDRequest]() +## func [NewGetAuditLogByIDRequest]() ```go func NewGetAuditLogByIDRequest(server string, id openapi_types.UUID) (*http.Request, error) @@ -361,7 +388,7 @@ func NewGetAuditLogByIDRequest(server string, id openapi_types.UUID) (*http.Requ NewGetAuditLogByIDRequest generates requests for GetAuditLogByID -## func [NewGetAuditLogsRequest]() +## func [NewGetAuditLogsRequest]() ```go func NewGetAuditLogsRequest(server string, params *GetAuditLogsParams) (*http.Request, error) @@ -370,7 +397,7 @@ func NewGetAuditLogsRequest(server string, params *GetAuditLogsParams) (*http.Re NewGetAuditLogsRequest generates requests for GetAuditLogs -## func [NewGetHealthReadyRequest]() +## func [NewGetHealthReadyRequest]() ```go func NewGetHealthReadyRequest(server string) (*http.Request, error) @@ -379,7 +406,7 @@ func NewGetHealthReadyRequest(server string) (*http.Request, error) NewGetHealthReadyRequest generates requests for GetHealthReady -## func [NewGetHealthRequest]() +## func [NewGetHealthRequest]() ```go func NewGetHealthRequest(server string) (*http.Request, error) @@ -388,7 +415,7 @@ func NewGetHealthRequest(server string) (*http.Request, error) NewGetHealthRequest generates requests for GetHealth -## func [NewGetHealthStatusRequest]() +## func [NewGetHealthStatusRequest]() ```go func NewGetHealthStatusRequest(server string) (*http.Request, error) @@ -397,7 +424,7 @@ func NewGetHealthStatusRequest(server string) (*http.Request, error) NewGetHealthStatusRequest generates requests for GetHealthStatus -## func [NewGetJobByIDRequest]() +## func [NewGetJobByIDRequest]() ```go func NewGetJobByIDRequest(server string, id openapi_types.UUID) (*http.Request, error) @@ -406,7 +433,7 @@ func NewGetJobByIDRequest(server string, id openapi_types.UUID) (*http.Request, NewGetJobByIDRequest generates requests for GetJobByID -## func [NewGetJobRequest]() +## func [NewGetJobRequest]() ```go func NewGetJobRequest(server string, params *GetJobParams) (*http.Request, error) @@ -415,7 +442,7 @@ func NewGetJobRequest(server string, params *GetJobParams) (*http.Request, error NewGetJobRequest generates requests for GetJob -## func [NewGetJobStatusRequest]() +## func [NewGetJobStatusRequest]() ```go func NewGetJobStatusRequest(server string) (*http.Request, error) @@ -424,7 +451,7 @@ func NewGetJobStatusRequest(server string) (*http.Request, error) NewGetJobStatusRequest generates requests for GetJobStatus -## func [NewGetNodeDiskRequest]() +## func [NewGetNodeDiskRequest]() ```go func NewGetNodeDiskRequest(server string, hostname Hostname) (*http.Request, error) @@ -433,7 +460,7 @@ func NewGetNodeDiskRequest(server string, hostname Hostname) (*http.Request, err NewGetNodeDiskRequest generates requests for GetNodeDisk -## func [NewGetNodeHostnameRequest]() +## func [NewGetNodeHostnameRequest]() ```go func NewGetNodeHostnameRequest(server string, hostname Hostname) (*http.Request, error) @@ -442,7 +469,7 @@ func NewGetNodeHostnameRequest(server string, hostname Hostname) (*http.Request, NewGetNodeHostnameRequest generates requests for GetNodeHostname -## func [NewGetNodeLoadRequest]() +## func [NewGetNodeLoadRequest]() ```go func NewGetNodeLoadRequest(server string, hostname Hostname) (*http.Request, error) @@ -451,7 +478,7 @@ func NewGetNodeLoadRequest(server string, hostname Hostname) (*http.Request, err NewGetNodeLoadRequest generates requests for GetNodeLoad -## func [NewGetNodeMemoryRequest]() +## func [NewGetNodeMemoryRequest]() ```go func NewGetNodeMemoryRequest(server string, hostname Hostname) (*http.Request, error) @@ -460,7 +487,7 @@ func NewGetNodeMemoryRequest(server string, hostname Hostname) (*http.Request, e NewGetNodeMemoryRequest generates requests for GetNodeMemory -## func [NewGetNodeNetworkDNSByInterfaceRequest]() +## func [NewGetNodeNetworkDNSByInterfaceRequest]() ```go func NewGetNodeNetworkDNSByInterfaceRequest(server string, hostname Hostname, interfaceName string) (*http.Request, error) @@ -469,7 +496,7 @@ func NewGetNodeNetworkDNSByInterfaceRequest(server string, hostname Hostname, in NewGetNodeNetworkDNSByInterfaceRequest generates requests for GetNodeNetworkDNSByInterface -## func [NewGetNodeOSRequest]() +## func [NewGetNodeOSRequest]() ```go func NewGetNodeOSRequest(server string, hostname Hostname) (*http.Request, error) @@ -478,7 +505,7 @@ func NewGetNodeOSRequest(server string, hostname Hostname) (*http.Request, error NewGetNodeOSRequest generates requests for GetNodeOS -## func [NewGetNodeStatusRequest]() +## func [NewGetNodeStatusRequest]() ```go func NewGetNodeStatusRequest(server string, hostname Hostname) (*http.Request, error) @@ -487,7 +514,7 @@ func NewGetNodeStatusRequest(server string, hostname Hostname) (*http.Request, e NewGetNodeStatusRequest generates requests for GetNodeStatus -## func [NewGetNodeUptimeRequest]() +## func [NewGetNodeUptimeRequest]() ```go func NewGetNodeUptimeRequest(server string, hostname Hostname) (*http.Request, error) @@ -496,7 +523,7 @@ func NewGetNodeUptimeRequest(server string, hostname Hostname) (*http.Request, e NewGetNodeUptimeRequest generates requests for GetNodeUptime -## func [NewGetVersionRequest]() +## func [NewGetVersionRequest]() ```go func NewGetVersionRequest(server string) (*http.Request, error) @@ -505,7 +532,7 @@ func NewGetVersionRequest(server string) (*http.Request, error) NewGetVersionRequest generates requests for GetVersion -## func [NewPostJobRequest]() +## func [NewPostJobRequest]() ```go func NewPostJobRequest(server string, body PostJobJSONRequestBody) (*http.Request, error) @@ -514,7 +541,7 @@ func NewPostJobRequest(server string, body PostJobJSONRequestBody) (*http.Reques NewPostJobRequest calls the generic PostJob builder with application/json body -## func [NewPostJobRequestWithBody]() +## func [NewPostJobRequestWithBody]() ```go func NewPostJobRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) @@ -523,7 +550,7 @@ func NewPostJobRequestWithBody(server string, contentType string, body io.Reader NewPostJobRequestWithBody generates requests for PostJob with any type of body -## func [NewPostNodeCommandExecRequest]() +## func [NewPostNodeCommandExecRequest]() ```go func NewPostNodeCommandExecRequest(server string, hostname Hostname, body PostNodeCommandExecJSONRequestBody) (*http.Request, error) @@ -532,7 +559,7 @@ func NewPostNodeCommandExecRequest(server string, hostname Hostname, body PostNo NewPostNodeCommandExecRequest calls the generic PostNodeCommandExec builder with application/json body -## func [NewPostNodeCommandExecRequestWithBody]() +## func [NewPostNodeCommandExecRequestWithBody]() ```go func NewPostNodeCommandExecRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) @@ -541,7 +568,7 @@ func NewPostNodeCommandExecRequestWithBody(server string, hostname Hostname, con NewPostNodeCommandExecRequestWithBody generates requests for PostNodeCommandExec with any type of body -## func [NewPostNodeCommandShellRequest]() +## func [NewPostNodeCommandShellRequest]() ```go func NewPostNodeCommandShellRequest(server string, hostname Hostname, body PostNodeCommandShellJSONRequestBody) (*http.Request, error) @@ -550,7 +577,7 @@ func NewPostNodeCommandShellRequest(server string, hostname Hostname, body PostN NewPostNodeCommandShellRequest calls the generic PostNodeCommandShell builder with application/json body -## func [NewPostNodeCommandShellRequestWithBody]() +## func [NewPostNodeCommandShellRequestWithBody]() ```go func NewPostNodeCommandShellRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) @@ -559,7 +586,7 @@ func NewPostNodeCommandShellRequestWithBody(server string, hostname Hostname, co NewPostNodeCommandShellRequestWithBody generates requests for PostNodeCommandShell with any type of body -## func [NewPostNodeNetworkPingRequest]() +## func [NewPostNodeNetworkPingRequest]() ```go func NewPostNodeNetworkPingRequest(server string, hostname Hostname, body PostNodeNetworkPingJSONRequestBody) (*http.Request, error) @@ -568,7 +595,7 @@ func NewPostNodeNetworkPingRequest(server string, hostname Hostname, body PostNo NewPostNodeNetworkPingRequest calls the generic PostNodeNetworkPing builder with application/json body -## func [NewPostNodeNetworkPingRequestWithBody]() +## func [NewPostNodeNetworkPingRequestWithBody]() ```go func NewPostNodeNetworkPingRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) @@ -577,7 +604,7 @@ func NewPostNodeNetworkPingRequestWithBody(server string, hostname Hostname, con NewPostNodeNetworkPingRequestWithBody generates requests for PostNodeNetworkPing with any type of body -## func [NewPutNodeNetworkDNSRequest]() +## func [NewPutNodeNetworkDNSRequest]() ```go func NewPutNodeNetworkDNSRequest(server string, hostname Hostname, body PutNodeNetworkDNSJSONRequestBody) (*http.Request, error) @@ -586,7 +613,7 @@ func NewPutNodeNetworkDNSRequest(server string, hostname Hostname, body PutNodeN NewPutNodeNetworkDNSRequest calls the generic PutNodeNetworkDNS builder with application/json body -## func [NewPutNodeNetworkDNSRequestWithBody]() +## func [NewPutNodeNetworkDNSRequestWithBody]() ```go func NewPutNodeNetworkDNSRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) @@ -595,7 +622,7 @@ func NewPutNodeNetworkDNSRequestWithBody(server string, hostname Hostname, conte NewPutNodeNetworkDNSRequestWithBody generates requests for PutNodeNetworkDNS with any type of body -## func [NewRetryJobByIDRequest]() +## func [NewRetryJobByIDRequest]() ```go func NewRetryJobByIDRequest(server string, id openapi_types.UUID, body RetryJobByIDJSONRequestBody) (*http.Request, error) @@ -604,7 +631,7 @@ func NewRetryJobByIDRequest(server string, id openapi_types.UUID, body RetryJobB NewRetryJobByIDRequest calls the generic RetryJobByID builder with application/json body -## func [NewRetryJobByIDRequestWithBody]() +## func [NewRetryJobByIDRequestWithBody]() ```go func NewRetryJobByIDRequestWithBody(server string, id openapi_types.UUID, contentType string, body io.Reader) (*http.Request, error) @@ -612,8 +639,17 @@ func NewRetryJobByIDRequestWithBody(server string, id openapi_types.UUID, conten NewRetryJobByIDRequestWithBody generates requests for RetryJobByID with any type of body + +## func [NewUndrainAgentRequest]() + +```go +func NewUndrainAgentRequest(server string, hostname string) (*http.Request, error) +``` + +NewUndrainAgentRequest generates requests for UndrainAgent + -## type [AgentDetail]() +## type [AgentDetail]() AgentDetail defines model for AgentDetail. @@ -631,7 +667,7 @@ type AgentDetail struct { ``` -## type [AgentInfo]() +## type [AgentInfo]() AgentInfo defines model for AgentInfo. @@ -640,6 +676,9 @@ type AgentInfo struct { // Architecture CPU architecture. Architecture *string `json:"architecture,omitempty"` + // Conditions Evaluated node conditions. + Conditions *[]NodeCondition `json:"conditions,omitempty"` + // CpuCount Number of logical CPUs. CpuCount *int `json:"cpu_count,omitempty"` @@ -680,16 +719,41 @@ type AgentInfo struct { // StartedAt When the agent process started. StartedAt *time.Time `json:"started_at,omitempty"` + // State Agent scheduling state. + State *AgentInfoState `json:"state,omitempty"` + // Status The current status of the agent. Status AgentInfoStatus `json:"status"` + // Timeline Agent state transition history. + Timeline *[]TimelineEvent `json:"timeline,omitempty"` + // Uptime The system uptime. Uptime *string `json:"uptime,omitempty"` } ``` + +## type [AgentInfoState]() + +AgentInfoState Agent scheduling state. + +```go +type AgentInfoState string +``` + +Defines values for AgentInfoState. + +```go +const ( + AgentInfoStateCordoned AgentInfoState = "Cordoned" + AgentInfoStateDraining AgentInfoState = "Draining" + AgentInfoStateReady AgentInfoState = "Ready" +) +``` + -## type [AgentInfoStatus]() +## type [AgentInfoStatus]() AgentInfoStatus The current status of the agent. @@ -697,17 +761,17 @@ AgentInfoStatus The current status of the agent. type AgentInfoStatus string ``` -Defines values for AgentInfoStatus. +Defines values for AgentInfoStatus. ```go const ( - NotReady AgentInfoStatus = "NotReady" - Ready AgentInfoStatus = "Ready" + AgentInfoStatusNotReady AgentInfoStatus = "NotReady" + AgentInfoStatusReady AgentInfoStatus = "Ready" ) ``` -## type [AgentStats]() +## type [AgentStats]() AgentStats defines model for AgentStats. @@ -725,7 +789,7 @@ type AgentStats struct { ``` -## type [AuditEntry]() +## type [AuditEntry]() AuditEntry defines model for AuditEntry. @@ -764,7 +828,7 @@ type AuditEntry struct { ``` -## type [AuditEntryResponse]() +## type [AuditEntryResponse]() AuditEntryResponse defines model for AuditEntryResponse. @@ -775,7 +839,7 @@ type AuditEntryResponse struct { ``` -## type [Client]() +## type [Client]() Client which conforms to the OpenAPI3 specification for this service. @@ -798,7 +862,7 @@ type Client struct { ``` -### func [NewClient]() +### func [NewClient]() ```go func NewClient(server string, opts ...ClientOption) (*Client, error) @@ -807,7 +871,7 @@ func NewClient(server string, opts ...ClientOption) (*Client, error) Creates a new Client, with reasonable defaults -### func \(\*Client\) [DeleteJobByID]() +### func \(\*Client\) [DeleteJobByID]() ```go func (c *Client) DeleteJobByID(ctx context.Context, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -815,8 +879,17 @@ func (c *Client) DeleteJobByID(ctx context.Context, id openapi_types.UUID, reqEd + +### func \(\*Client\) [DrainAgent]() + +```go +func (c *Client) DrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) +``` + + + -### func \(\*Client\) [GetAgent]() +### func \(\*Client\) [GetAgent]() ```go func (c *Client) GetAgent(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -825,7 +898,7 @@ func (c *Client) GetAgent(ctx context.Context, reqEditors ...RequestEditorFn) (* -### func \(\*Client\) [GetAgentDetails]() +### func \(\*Client\) [GetAgentDetails]() ```go func (c *Client) GetAgentDetails(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -834,7 +907,7 @@ func (c *Client) GetAgentDetails(ctx context.Context, hostname string, reqEditor -### func \(\*Client\) [GetAuditExport]() +### func \(\*Client\) [GetAuditExport]() ```go func (c *Client) GetAuditExport(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -843,7 +916,7 @@ func (c *Client) GetAuditExport(ctx context.Context, reqEditors ...RequestEditor -### func \(\*Client\) [GetAuditLogByID]() +### func \(\*Client\) [GetAuditLogByID]() ```go func (c *Client) GetAuditLogByID(ctx context.Context, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -852,7 +925,7 @@ func (c *Client) GetAuditLogByID(ctx context.Context, id openapi_types.UUID, req -### func \(\*Client\) [GetAuditLogs]() +### func \(\*Client\) [GetAuditLogs]() ```go func (c *Client) GetAuditLogs(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -861,7 +934,7 @@ func (c *Client) GetAuditLogs(ctx context.Context, params *GetAuditLogsParams, r -### func \(\*Client\) [GetHealth]() +### func \(\*Client\) [GetHealth]() ```go func (c *Client) GetHealth(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -870,7 +943,7 @@ func (c *Client) GetHealth(ctx context.Context, reqEditors ...RequestEditorFn) ( -### func \(\*Client\) [GetHealthReady]() +### func \(\*Client\) [GetHealthReady]() ```go func (c *Client) GetHealthReady(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -879,7 +952,7 @@ func (c *Client) GetHealthReady(ctx context.Context, reqEditors ...RequestEditor -### func \(\*Client\) [GetHealthStatus]() +### func \(\*Client\) [GetHealthStatus]() ```go func (c *Client) GetHealthStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -888,7 +961,7 @@ func (c *Client) GetHealthStatus(ctx context.Context, reqEditors ...RequestEdito -### func \(\*Client\) [GetJob]() +### func \(\*Client\) [GetJob]() ```go func (c *Client) GetJob(ctx context.Context, params *GetJobParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -897,7 +970,7 @@ func (c *Client) GetJob(ctx context.Context, params *GetJobParams, reqEditors .. -### func \(\*Client\) [GetJobByID]() +### func \(\*Client\) [GetJobByID]() ```go func (c *Client) GetJobByID(ctx context.Context, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -906,7 +979,7 @@ func (c *Client) GetJobByID(ctx context.Context, id openapi_types.UUID, reqEdito -### func \(\*Client\) [GetJobStatus]() +### func \(\*Client\) [GetJobStatus]() ```go func (c *Client) GetJobStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -915,7 +988,7 @@ func (c *Client) GetJobStatus(ctx context.Context, reqEditors ...RequestEditorFn -### func \(\*Client\) [GetNodeDisk]() +### func \(\*Client\) [GetNodeDisk]() ```go func (c *Client) GetNodeDisk(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -924,7 +997,7 @@ func (c *Client) GetNodeDisk(ctx context.Context, hostname Hostname, reqEditors -### func \(\*Client\) [GetNodeHostname]() +### func \(\*Client\) [GetNodeHostname]() ```go func (c *Client) GetNodeHostname(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -933,7 +1006,7 @@ func (c *Client) GetNodeHostname(ctx context.Context, hostname Hostname, reqEdit -### func \(\*Client\) [GetNodeLoad]() +### func \(\*Client\) [GetNodeLoad]() ```go func (c *Client) GetNodeLoad(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -942,7 +1015,7 @@ func (c *Client) GetNodeLoad(ctx context.Context, hostname Hostname, reqEditors -### func \(\*Client\) [GetNodeMemory]() +### func \(\*Client\) [GetNodeMemory]() ```go func (c *Client) GetNodeMemory(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -951,7 +1024,7 @@ func (c *Client) GetNodeMemory(ctx context.Context, hostname Hostname, reqEditor -### func \(\*Client\) [GetNodeNetworkDNSByInterface]() +### func \(\*Client\) [GetNodeNetworkDNSByInterface]() ```go func (c *Client) GetNodeNetworkDNSByInterface(ctx context.Context, hostname Hostname, interfaceName string, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -960,7 +1033,7 @@ func (c *Client) GetNodeNetworkDNSByInterface(ctx context.Context, hostname Host -### func \(\*Client\) [GetNodeOS]() +### func \(\*Client\) [GetNodeOS]() ```go func (c *Client) GetNodeOS(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -969,7 +1042,7 @@ func (c *Client) GetNodeOS(ctx context.Context, hostname Hostname, reqEditors .. -### func \(\*Client\) [GetNodeStatus]() +### func \(\*Client\) [GetNodeStatus]() ```go func (c *Client) GetNodeStatus(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -978,7 +1051,7 @@ func (c *Client) GetNodeStatus(ctx context.Context, hostname Hostname, reqEditor -### func \(\*Client\) [GetNodeUptime]() +### func \(\*Client\) [GetNodeUptime]() ```go func (c *Client) GetNodeUptime(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -987,7 +1060,7 @@ func (c *Client) GetNodeUptime(ctx context.Context, hostname Hostname, reqEditor -### func \(\*Client\) [GetVersion]() +### func \(\*Client\) [GetVersion]() ```go func (c *Client) GetVersion(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -996,7 +1069,7 @@ func (c *Client) GetVersion(ctx context.Context, reqEditors ...RequestEditorFn) -### func \(\*Client\) [PostJob]() +### func \(\*Client\) [PostJob]() ```go func (c *Client) PostJob(ctx context.Context, body PostJobJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1005,7 +1078,7 @@ func (c *Client) PostJob(ctx context.Context, body PostJobJSONRequestBody, reqEd -### func \(\*Client\) [PostJobWithBody]() +### func \(\*Client\) [PostJobWithBody]() ```go func (c *Client) PostJobWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1014,7 +1087,7 @@ func (c *Client) PostJobWithBody(ctx context.Context, contentType string, body i -### func \(\*Client\) [PostNodeCommandExec]() +### func \(\*Client\) [PostNodeCommandExec]() ```go func (c *Client) PostNodeCommandExec(ctx context.Context, hostname Hostname, body PostNodeCommandExecJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1023,7 +1096,7 @@ func (c *Client) PostNodeCommandExec(ctx context.Context, hostname Hostname, bod -### func \(\*Client\) [PostNodeCommandExecWithBody]() +### func \(\*Client\) [PostNodeCommandExecWithBody]() ```go func (c *Client) PostNodeCommandExecWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1032,7 +1105,7 @@ func (c *Client) PostNodeCommandExecWithBody(ctx context.Context, hostname Hostn -### func \(\*Client\) [PostNodeCommandShell]() +### func \(\*Client\) [PostNodeCommandShell]() ```go func (c *Client) PostNodeCommandShell(ctx context.Context, hostname Hostname, body PostNodeCommandShellJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1041,7 +1114,7 @@ func (c *Client) PostNodeCommandShell(ctx context.Context, hostname Hostname, bo -### func \(\*Client\) [PostNodeCommandShellWithBody]() +### func \(\*Client\) [PostNodeCommandShellWithBody]() ```go func (c *Client) PostNodeCommandShellWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1050,7 +1123,7 @@ func (c *Client) PostNodeCommandShellWithBody(ctx context.Context, hostname Host -### func \(\*Client\) [PostNodeNetworkPing]() +### func \(\*Client\) [PostNodeNetworkPing]() ```go func (c *Client) PostNodeNetworkPing(ctx context.Context, hostname Hostname, body PostNodeNetworkPingJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1059,7 +1132,7 @@ func (c *Client) PostNodeNetworkPing(ctx context.Context, hostname Hostname, bod -### func \(\*Client\) [PostNodeNetworkPingWithBody]() +### func \(\*Client\) [PostNodeNetworkPingWithBody]() ```go func (c *Client) PostNodeNetworkPingWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1068,7 +1141,7 @@ func (c *Client) PostNodeNetworkPingWithBody(ctx context.Context, hostname Hostn -### func \(\*Client\) [PutNodeNetworkDNS]() +### func \(\*Client\) [PutNodeNetworkDNS]() ```go func (c *Client) PutNodeNetworkDNS(ctx context.Context, hostname Hostname, body PutNodeNetworkDNSJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1077,7 +1150,7 @@ func (c *Client) PutNodeNetworkDNS(ctx context.Context, hostname Hostname, body -### func \(\*Client\) [PutNodeNetworkDNSWithBody]() +### func \(\*Client\) [PutNodeNetworkDNSWithBody]() ```go func (c *Client) PutNodeNetworkDNSWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1086,7 +1159,7 @@ func (c *Client) PutNodeNetworkDNSWithBody(ctx context.Context, hostname Hostnam -### func \(\*Client\) [RetryJobByID]() +### func \(\*Client\) [RetryJobByID]() ```go func (c *Client) RetryJobByID(ctx context.Context, id openapi_types.UUID, body RetryJobByIDJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1095,7 +1168,7 @@ func (c *Client) RetryJobByID(ctx context.Context, id openapi_types.UUID, body R -### func \(\*Client\) [RetryJobByIDWithBody]() +### func \(\*Client\) [RetryJobByIDWithBody]() ```go func (c *Client) RetryJobByIDWithBody(ctx context.Context, id openapi_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1103,8 +1176,17 @@ func (c *Client) RetryJobByIDWithBody(ctx context.Context, id openapi_types.UUID + +### func \(\*Client\) [UndrainAgent]() + +```go +func (c *Client) UndrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) +``` + + + -## type [ClientInterface]() +## type [ClientInterface]() The interface specification for the client above. @@ -1116,6 +1198,12 @@ type ClientInterface interface { // GetAgentDetails request GetAgentDetails(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) + // DrainAgent request + DrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UndrainAgent request + UndrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetAuditLogs request GetAuditLogs(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1206,7 +1294,7 @@ type ClientInterface interface { ``` -## type [ClientOption]() +## type [ClientOption]() ClientOption allows setting custom parameters during construction @@ -1215,7 +1303,7 @@ type ClientOption func(*Client) error ``` -### func [WithBaseURL]() +### func [WithBaseURL]() ```go func WithBaseURL(baseURL string) ClientOption @@ -1224,7 +1312,7 @@ func WithBaseURL(baseURL string) ClientOption WithBaseURL overrides the baseURL. -### func [WithHTTPClient]() +### func [WithHTTPClient]() ```go func WithHTTPClient(doer HttpRequestDoer) ClientOption @@ -1233,7 +1321,7 @@ func WithHTTPClient(doer HttpRequestDoer) ClientOption WithHTTPClient allows overriding the default Doer, which is automatically created using http.Client. This is useful for tests. -### func [WithRequestEditorFn]() +### func [WithRequestEditorFn]() ```go func WithRequestEditorFn(fn RequestEditorFn) ClientOption @@ -1242,7 +1330,7 @@ func WithRequestEditorFn(fn RequestEditorFn) ClientOption WithRequestEditorFn allows setting up a callback function, which will be called right before sending the request. This can be used to mutate the request. -## type [ClientWithResponses]() +## type [ClientWithResponses]() ClientWithResponses builds on ClientInterface to offer response payloads @@ -1253,7 +1341,7 @@ type ClientWithResponses struct { ``` -### func [NewClientWithResponses]() +### func [NewClientWithResponses]() ```go func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) @@ -1262,7 +1350,7 @@ func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithRes NewClientWithResponses creates a new ClientWithResponses, which wraps Client with return type handling -### func \(\*ClientWithResponses\) [DeleteJobByIDWithResponse]() +### func \(\*ClientWithResponses\) [DeleteJobByIDWithResponse]() ```go func (c *ClientWithResponses) DeleteJobByIDWithResponse(ctx context.Context, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*DeleteJobByIDResponse, error) @@ -1270,8 +1358,17 @@ func (c *ClientWithResponses) DeleteJobByIDWithResponse(ctx context.Context, id DeleteJobByIDWithResponse request returning \*DeleteJobByIDResponse + +### func \(\*ClientWithResponses\) [DrainAgentWithResponse]() + +```go +func (c *ClientWithResponses) DrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*DrainAgentResponse, error) +``` + +DrainAgentWithResponse request returning \*DrainAgentResponse + -### func \(\*ClientWithResponses\) [GetAgentDetailsWithResponse]() +### func \(\*ClientWithResponses\) [GetAgentDetailsWithResponse]() ```go func (c *ClientWithResponses) GetAgentDetailsWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*GetAgentDetailsResponse, error) @@ -1280,7 +1377,7 @@ func (c *ClientWithResponses) GetAgentDetailsWithResponse(ctx context.Context, h GetAgentDetailsWithResponse request returning \*GetAgentDetailsResponse -### func \(\*ClientWithResponses\) [GetAgentWithResponse]() +### func \(\*ClientWithResponses\) [GetAgentWithResponse]() ```go func (c *ClientWithResponses) GetAgentWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetAgentResponse, error) @@ -1289,7 +1386,7 @@ func (c *ClientWithResponses) GetAgentWithResponse(ctx context.Context, reqEdito GetAgentWithResponse request returning \*GetAgentResponse -### func \(\*ClientWithResponses\) [GetAuditExportWithResponse]() +### func \(\*ClientWithResponses\) [GetAuditExportWithResponse]() ```go func (c *ClientWithResponses) GetAuditExportWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetAuditExportResponse, error) @@ -1298,7 +1395,7 @@ func (c *ClientWithResponses) GetAuditExportWithResponse(ctx context.Context, re GetAuditExportWithResponse request returning \*GetAuditExportResponse -### func \(\*ClientWithResponses\) [GetAuditLogByIDWithResponse]() +### func \(\*ClientWithResponses\) [GetAuditLogByIDWithResponse]() ```go func (c *ClientWithResponses) GetAuditLogByIDWithResponse(ctx context.Context, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*GetAuditLogByIDResponse, error) @@ -1307,7 +1404,7 @@ func (c *ClientWithResponses) GetAuditLogByIDWithResponse(ctx context.Context, i GetAuditLogByIDWithResponse request returning \*GetAuditLogByIDResponse -### func \(\*ClientWithResponses\) [GetAuditLogsWithResponse]() +### func \(\*ClientWithResponses\) [GetAuditLogsWithResponse]() ```go func (c *ClientWithResponses) GetAuditLogsWithResponse(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*GetAuditLogsResponse, error) @@ -1316,7 +1413,7 @@ func (c *ClientWithResponses) GetAuditLogsWithResponse(ctx context.Context, para GetAuditLogsWithResponse request returning \*GetAuditLogsResponse -### func \(\*ClientWithResponses\) [GetHealthReadyWithResponse]() +### func \(\*ClientWithResponses\) [GetHealthReadyWithResponse]() ```go func (c *ClientWithResponses) GetHealthReadyWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetHealthReadyResponse, error) @@ -1325,7 +1422,7 @@ func (c *ClientWithResponses) GetHealthReadyWithResponse(ctx context.Context, re GetHealthReadyWithResponse request returning \*GetHealthReadyResponse -### func \(\*ClientWithResponses\) [GetHealthStatusWithResponse]() +### func \(\*ClientWithResponses\) [GetHealthStatusWithResponse]() ```go func (c *ClientWithResponses) GetHealthStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetHealthStatusResponse, error) @@ -1334,7 +1431,7 @@ func (c *ClientWithResponses) GetHealthStatusWithResponse(ctx context.Context, r GetHealthStatusWithResponse request returning \*GetHealthStatusResponse -### func \(\*ClientWithResponses\) [GetHealthWithResponse]() +### func \(\*ClientWithResponses\) [GetHealthWithResponse]() ```go func (c *ClientWithResponses) GetHealthWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetHealthResponse, error) @@ -1343,7 +1440,7 @@ func (c *ClientWithResponses) GetHealthWithResponse(ctx context.Context, reqEdit GetHealthWithResponse request returning \*GetHealthResponse -### func \(\*ClientWithResponses\) [GetJobByIDWithResponse]() +### func \(\*ClientWithResponses\) [GetJobByIDWithResponse]() ```go func (c *ClientWithResponses) GetJobByIDWithResponse(ctx context.Context, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*GetJobByIDResponse, error) @@ -1352,7 +1449,7 @@ func (c *ClientWithResponses) GetJobByIDWithResponse(ctx context.Context, id ope GetJobByIDWithResponse request returning \*GetJobByIDResponse -### func \(\*ClientWithResponses\) [GetJobStatusWithResponse]() +### func \(\*ClientWithResponses\) [GetJobStatusWithResponse]() ```go func (c *ClientWithResponses) GetJobStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetJobStatusResponse, error) @@ -1361,7 +1458,7 @@ func (c *ClientWithResponses) GetJobStatusWithResponse(ctx context.Context, reqE GetJobStatusWithResponse request returning \*GetJobStatusResponse -### func \(\*ClientWithResponses\) [GetJobWithResponse]() +### func \(\*ClientWithResponses\) [GetJobWithResponse]() ```go func (c *ClientWithResponses) GetJobWithResponse(ctx context.Context, params *GetJobParams, reqEditors ...RequestEditorFn) (*GetJobResponse, error) @@ -1370,7 +1467,7 @@ func (c *ClientWithResponses) GetJobWithResponse(ctx context.Context, params *Ge GetJobWithResponse request returning \*GetJobResponse -### func \(\*ClientWithResponses\) [GetNodeDiskWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeDiskWithResponse]() ```go func (c *ClientWithResponses) GetNodeDiskWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeDiskResponse, error) @@ -1379,7 +1476,7 @@ func (c *ClientWithResponses) GetNodeDiskWithResponse(ctx context.Context, hostn GetNodeDiskWithResponse request returning \*GetNodeDiskResponse -### func \(\*ClientWithResponses\) [GetNodeHostnameWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeHostnameWithResponse]() ```go func (c *ClientWithResponses) GetNodeHostnameWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeHostnameResponse, error) @@ -1388,7 +1485,7 @@ func (c *ClientWithResponses) GetNodeHostnameWithResponse(ctx context.Context, h GetNodeHostnameWithResponse request returning \*GetNodeHostnameResponse -### func \(\*ClientWithResponses\) [GetNodeLoadWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeLoadWithResponse]() ```go func (c *ClientWithResponses) GetNodeLoadWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeLoadResponse, error) @@ -1397,7 +1494,7 @@ func (c *ClientWithResponses) GetNodeLoadWithResponse(ctx context.Context, hostn GetNodeLoadWithResponse request returning \*GetNodeLoadResponse -### func \(\*ClientWithResponses\) [GetNodeMemoryWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeMemoryWithResponse]() ```go func (c *ClientWithResponses) GetNodeMemoryWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeMemoryResponse, error) @@ -1406,7 +1503,7 @@ func (c *ClientWithResponses) GetNodeMemoryWithResponse(ctx context.Context, hos GetNodeMemoryWithResponse request returning \*GetNodeMemoryResponse -### func \(\*ClientWithResponses\) [GetNodeNetworkDNSByInterfaceWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeNetworkDNSByInterfaceWithResponse]() ```go func (c *ClientWithResponses) GetNodeNetworkDNSByInterfaceWithResponse(ctx context.Context, hostname Hostname, interfaceName string, reqEditors ...RequestEditorFn) (*GetNodeNetworkDNSByInterfaceResponse, error) @@ -1415,7 +1512,7 @@ func (c *ClientWithResponses) GetNodeNetworkDNSByInterfaceWithResponse(ctx conte GetNodeNetworkDNSByInterfaceWithResponse request returning \*GetNodeNetworkDNSByInterfaceResponse -### func \(\*ClientWithResponses\) [GetNodeOSWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeOSWithResponse]() ```go func (c *ClientWithResponses) GetNodeOSWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeOSResponse, error) @@ -1424,7 +1521,7 @@ func (c *ClientWithResponses) GetNodeOSWithResponse(ctx context.Context, hostnam GetNodeOSWithResponse request returning \*GetNodeOSResponse -### func \(\*ClientWithResponses\) [GetNodeStatusWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeStatusWithResponse]() ```go func (c *ClientWithResponses) GetNodeStatusWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeStatusResponse, error) @@ -1433,7 +1530,7 @@ func (c *ClientWithResponses) GetNodeStatusWithResponse(ctx context.Context, hos GetNodeStatusWithResponse request returning \*GetNodeStatusResponse -### func \(\*ClientWithResponses\) [GetNodeUptimeWithResponse]() +### func \(\*ClientWithResponses\) [GetNodeUptimeWithResponse]() ```go func (c *ClientWithResponses) GetNodeUptimeWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeUptimeResponse, error) @@ -1442,7 +1539,7 @@ func (c *ClientWithResponses) GetNodeUptimeWithResponse(ctx context.Context, hos GetNodeUptimeWithResponse request returning \*GetNodeUptimeResponse -### func \(\*ClientWithResponses\) [GetVersionWithResponse]() +### func \(\*ClientWithResponses\) [GetVersionWithResponse]() ```go func (c *ClientWithResponses) GetVersionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetVersionResponse, error) @@ -1451,7 +1548,7 @@ func (c *ClientWithResponses) GetVersionWithResponse(ctx context.Context, reqEdi GetVersionWithResponse request returning \*GetVersionResponse -### func \(\*ClientWithResponses\) [PostJobWithBodyWithResponse]() +### func \(\*ClientWithResponses\) [PostJobWithBodyWithResponse]() ```go func (c *ClientWithResponses) PostJobWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostJobResponse, error) @@ -1460,7 +1557,7 @@ func (c *ClientWithResponses) PostJobWithBodyWithResponse(ctx context.Context, c PostJobWithBodyWithResponse request with arbitrary body returning \*PostJobResponse -### func \(\*ClientWithResponses\) [PostJobWithResponse]() +### func \(\*ClientWithResponses\) [PostJobWithResponse]() ```go func (c *ClientWithResponses) PostJobWithResponse(ctx context.Context, body PostJobJSONRequestBody, reqEditors ...RequestEditorFn) (*PostJobResponse, error) @@ -1469,7 +1566,7 @@ func (c *ClientWithResponses) PostJobWithResponse(ctx context.Context, body Post -### func \(\*ClientWithResponses\) [PostNodeCommandExecWithBodyWithResponse]() +### func \(\*ClientWithResponses\) [PostNodeCommandExecWithBodyWithResponse]() ```go func (c *ClientWithResponses) PostNodeCommandExecWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeCommandExecResponse, error) @@ -1478,7 +1575,7 @@ func (c *ClientWithResponses) PostNodeCommandExecWithBodyWithResponse(ctx contex PostNodeCommandExecWithBodyWithResponse request with arbitrary body returning \*PostNodeCommandExecResponse -### func \(\*ClientWithResponses\) [PostNodeCommandExecWithResponse]() +### func \(\*ClientWithResponses\) [PostNodeCommandExecWithResponse]() ```go func (c *ClientWithResponses) PostNodeCommandExecWithResponse(ctx context.Context, hostname Hostname, body PostNodeCommandExecJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeCommandExecResponse, error) @@ -1487,7 +1584,7 @@ func (c *ClientWithResponses) PostNodeCommandExecWithResponse(ctx context.Contex -### func \(\*ClientWithResponses\) [PostNodeCommandShellWithBodyWithResponse]() +### func \(\*ClientWithResponses\) [PostNodeCommandShellWithBodyWithResponse]() ```go func (c *ClientWithResponses) PostNodeCommandShellWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeCommandShellResponse, error) @@ -1496,7 +1593,7 @@ func (c *ClientWithResponses) PostNodeCommandShellWithBodyWithResponse(ctx conte PostNodeCommandShellWithBodyWithResponse request with arbitrary body returning \*PostNodeCommandShellResponse -### func \(\*ClientWithResponses\) [PostNodeCommandShellWithResponse]() +### func \(\*ClientWithResponses\) [PostNodeCommandShellWithResponse]() ```go func (c *ClientWithResponses) PostNodeCommandShellWithResponse(ctx context.Context, hostname Hostname, body PostNodeCommandShellJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeCommandShellResponse, error) @@ -1505,7 +1602,7 @@ func (c *ClientWithResponses) PostNodeCommandShellWithResponse(ctx context.Conte -### func \(\*ClientWithResponses\) [PostNodeNetworkPingWithBodyWithResponse]() +### func \(\*ClientWithResponses\) [PostNodeNetworkPingWithBodyWithResponse]() ```go func (c *ClientWithResponses) PostNodeNetworkPingWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeNetworkPingResponse, error) @@ -1514,7 +1611,7 @@ func (c *ClientWithResponses) PostNodeNetworkPingWithBodyWithResponse(ctx contex PostNodeNetworkPingWithBodyWithResponse request with arbitrary body returning \*PostNodeNetworkPingResponse -### func \(\*ClientWithResponses\) [PostNodeNetworkPingWithResponse]() +### func \(\*ClientWithResponses\) [PostNodeNetworkPingWithResponse]() ```go func (c *ClientWithResponses) PostNodeNetworkPingWithResponse(ctx context.Context, hostname Hostname, body PostNodeNetworkPingJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeNetworkPingResponse, error) @@ -1523,7 +1620,7 @@ func (c *ClientWithResponses) PostNodeNetworkPingWithResponse(ctx context.Contex -### func \(\*ClientWithResponses\) [PutNodeNetworkDNSWithBodyWithResponse]() +### func \(\*ClientWithResponses\) [PutNodeNetworkDNSWithBodyWithResponse]() ```go func (c *ClientWithResponses) PutNodeNetworkDNSWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutNodeNetworkDNSResponse, error) @@ -1532,7 +1629,7 @@ func (c *ClientWithResponses) PutNodeNetworkDNSWithBodyWithResponse(ctx context. PutNodeNetworkDNSWithBodyWithResponse request with arbitrary body returning \*PutNodeNetworkDNSResponse -### func \(\*ClientWithResponses\) [PutNodeNetworkDNSWithResponse]() +### func \(\*ClientWithResponses\) [PutNodeNetworkDNSWithResponse]() ```go func (c *ClientWithResponses) PutNodeNetworkDNSWithResponse(ctx context.Context, hostname Hostname, body PutNodeNetworkDNSJSONRequestBody, reqEditors ...RequestEditorFn) (*PutNodeNetworkDNSResponse, error) @@ -1541,7 +1638,7 @@ func (c *ClientWithResponses) PutNodeNetworkDNSWithResponse(ctx context.Context, -### func \(\*ClientWithResponses\) [RetryJobByIDWithBodyWithResponse]() +### func \(\*ClientWithResponses\) [RetryJobByIDWithBodyWithResponse]() ```go func (c *ClientWithResponses) RetryJobByIDWithBodyWithResponse(ctx context.Context, id openapi_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RetryJobByIDResponse, error) @@ -1550,7 +1647,7 @@ func (c *ClientWithResponses) RetryJobByIDWithBodyWithResponse(ctx context.Conte RetryJobByIDWithBodyWithResponse request with arbitrary body returning \*RetryJobByIDResponse -### func \(\*ClientWithResponses\) [RetryJobByIDWithResponse]() +### func \(\*ClientWithResponses\) [RetryJobByIDWithResponse]() ```go func (c *ClientWithResponses) RetryJobByIDWithResponse(ctx context.Context, id openapi_types.UUID, body RetryJobByIDJSONRequestBody, reqEditors ...RequestEditorFn) (*RetryJobByIDResponse, error) @@ -1558,8 +1655,17 @@ func (c *ClientWithResponses) RetryJobByIDWithResponse(ctx context.Context, id o + +### func \(\*ClientWithResponses\) [UndrainAgentWithResponse]() + +```go +func (c *ClientWithResponses) UndrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*UndrainAgentResponse, error) +``` + +UndrainAgentWithResponse request returning \*UndrainAgentResponse + -## type [ClientWithResponsesInterface]() +## type [ClientWithResponsesInterface]() ClientWithResponsesInterface is the interface specification for the client with responses above. @@ -1571,6 +1677,12 @@ type ClientWithResponsesInterface interface { // GetAgentDetailsWithResponse request GetAgentDetailsWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*GetAgentDetailsResponse, error) + // DrainAgentWithResponse request + DrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*DrainAgentResponse, error) + + // UndrainAgentWithResponse request + UndrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*UndrainAgentResponse, error) + // GetAuditLogsWithResponse request GetAuditLogsWithResponse(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*GetAuditLogsResponse, error) @@ -1661,7 +1773,7 @@ type ClientWithResponsesInterface interface { ``` -## type [CommandExecRequest]() +## type [CommandExecRequest]() CommandExecRequest defines model for CommandExecRequest. @@ -1682,7 +1794,7 @@ type CommandExecRequest struct { ``` -## type [CommandResultCollectionResponse]() +## type [CommandResultCollectionResponse]() CommandResultCollectionResponse defines model for CommandResultCollectionResponse. @@ -1695,7 +1807,7 @@ type CommandResultCollectionResponse struct { ``` -## type [CommandResultItem]() +## type [CommandResultItem]() CommandResultItem defines model for CommandResultItem. @@ -1725,7 +1837,7 @@ type CommandResultItem struct { ``` -## type [CommandShellRequest]() +## type [CommandShellRequest]() CommandShellRequest defines model for CommandShellRequest. @@ -1743,7 +1855,7 @@ type CommandShellRequest struct { ``` -## type [ComponentHealth]() +## type [ComponentHealth]() ComponentHealth defines model for ComponentHealth. @@ -1758,7 +1870,7 @@ type ComponentHealth struct { ``` -## type [ConsumerDetail]() +## type [ConsumerDetail]() ConsumerDetail defines model for ConsumerDetail. @@ -1779,7 +1891,7 @@ type ConsumerDetail struct { ``` -## type [ConsumerStats]() +## type [ConsumerStats]() ConsumerStats defines model for ConsumerStats. @@ -1794,7 +1906,7 @@ type ConsumerStats struct { ``` -## type [CreateJobRequest]() +## type [CreateJobRequest]() CreateJobRequest defines model for CreateJobRequest. @@ -1809,7 +1921,7 @@ type CreateJobRequest struct { ``` -## type [CreateJobResponse]() +## type [CreateJobResponse]() CreateJobResponse defines model for CreateJobResponse. @@ -1830,7 +1942,7 @@ type CreateJobResponse struct { ``` -## type [DNSConfigCollectionResponse]() +## type [DNSConfigCollectionResponse]() DNSConfigCollectionResponse defines model for DNSConfigCollectionResponse. @@ -1843,7 +1955,7 @@ type DNSConfigCollectionResponse struct { ``` -## type [DNSConfigResponse]() +## type [DNSConfigResponse]() DNSConfigResponse defines model for DNSConfigResponse. @@ -1864,7 +1976,7 @@ type DNSConfigResponse struct { ``` -## type [DNSConfigUpdateRequest]() +## type [DNSConfigUpdateRequest]() DNSConfigUpdateRequest defines model for DNSConfigUpdateRequest. @@ -1882,7 +1994,7 @@ type DNSConfigUpdateRequest struct { ``` -## type [DNSUpdateCollectionResponse]() +## type [DNSUpdateCollectionResponse]() DNSUpdateCollectionResponse defines model for DNSUpdateCollectionResponse. @@ -1895,7 +2007,7 @@ type DNSUpdateCollectionResponse struct { ``` -## type [DNSUpdateResultItem]() +## type [DNSUpdateResultItem]() DNSUpdateResultItem defines model for DNSUpdateResultItem. @@ -1910,7 +2022,7 @@ type DNSUpdateResultItem struct { ``` -## type [DNSUpdateResultItemStatus]() +## type [DNSUpdateResultItemStatus]() DNSUpdateResultItemStatus defines model for DNSUpdateResultItem.Status. @@ -1928,7 +2040,7 @@ const ( ``` -## type [DeleteJobByIDResponse]() +## type [DeleteJobByIDResponse]() @@ -1945,7 +2057,7 @@ type DeleteJobByIDResponse struct { ``` -### func [ParseDeleteJobByIDResponse]() +### func [ParseDeleteJobByIDResponse]() ```go func ParseDeleteJobByIDResponse(rsp *http.Response) (*DeleteJobByIDResponse, error) @@ -1954,7 +2066,7 @@ func ParseDeleteJobByIDResponse(rsp *http.Response) (*DeleteJobByIDResponse, err ParseDeleteJobByIDResponse parses an HTTP response from a DeleteJobByIDWithResponse call -### func \(DeleteJobByIDResponse\) [Status]() +### func \(DeleteJobByIDResponse\) [Status]() ```go func (r DeleteJobByIDResponse) Status() string @@ -1963,7 +2075,7 @@ func (r DeleteJobByIDResponse) Status() string Status returns HTTPResponse.Status -### func \(DeleteJobByIDResponse\) [StatusCode]() +### func \(DeleteJobByIDResponse\) [StatusCode]() ```go func (r DeleteJobByIDResponse) StatusCode() int @@ -1972,7 +2084,7 @@ func (r DeleteJobByIDResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [DiskCollectionResponse]() +## type [DiskCollectionResponse]() DiskCollectionResponse defines model for DiskCollectionResponse. @@ -1985,7 +2097,7 @@ type DiskCollectionResponse struct { ``` -## type [DiskResponse]() +## type [DiskResponse]() DiskResponse Local disk usage information. @@ -2006,7 +2118,7 @@ type DiskResponse struct { ``` -## type [DiskResultItem]() +## type [DiskResultItem]() DiskResultItem defines model for DiskResultItem. @@ -2024,7 +2136,7 @@ type DiskResultItem struct { ``` -## type [DisksResponse]() +## type [DisksResponse]() DisksResponse List of local disk usage information. @@ -2032,8 +2144,54 @@ DisksResponse List of local disk usage information. type DisksResponse = []DiskResponse ``` + +## type [DrainAgentResponse]() + + + +```go +type DrainAgentResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Message string `json:"message"` + } + JSON401 *ErrorResponse + JSON403 *ErrorResponse + JSON404 *ErrorResponse + JSON409 *ErrorResponse +} +``` + + +### func [ParseDrainAgentResponse]() + +```go +func ParseDrainAgentResponse(rsp *http.Response) (*DrainAgentResponse, error) +``` + +ParseDrainAgentResponse parses an HTTP response from a DrainAgentWithResponse call + + +### func \(DrainAgentResponse\) [Status]() + +```go +func (r DrainAgentResponse) Status() string +``` + +Status returns HTTPResponse.Status + + +### func \(DrainAgentResponse\) [StatusCode]() + +```go +func (r DrainAgentResponse) StatusCode() int +``` + +StatusCode returns HTTPResponse.StatusCode + -## type [ErrorResponse]() +## type [ErrorResponse]() ErrorResponse defines model for ErrorResponse. @@ -2051,7 +2209,7 @@ type ErrorResponse struct { ``` -## type [GetAgentDetailsResponse]() +## type [GetAgentDetailsResponse]() @@ -2068,7 +2226,7 @@ type GetAgentDetailsResponse struct { ``` -### func [ParseGetAgentDetailsResponse]() +### func [ParseGetAgentDetailsResponse]() ```go func ParseGetAgentDetailsResponse(rsp *http.Response) (*GetAgentDetailsResponse, error) @@ -2077,7 +2235,7 @@ func ParseGetAgentDetailsResponse(rsp *http.Response) (*GetAgentDetailsResponse, ParseGetAgentDetailsResponse parses an HTTP response from a GetAgentDetailsWithResponse call -### func \(GetAgentDetailsResponse\) [Status]() +### func \(GetAgentDetailsResponse\) [Status]() ```go func (r GetAgentDetailsResponse) Status() string @@ -2086,7 +2244,7 @@ func (r GetAgentDetailsResponse) Status() string Status returns HTTPResponse.Status -### func \(GetAgentDetailsResponse\) [StatusCode]() +### func \(GetAgentDetailsResponse\) [StatusCode]() ```go func (r GetAgentDetailsResponse) StatusCode() int @@ -2095,7 +2253,7 @@ func (r GetAgentDetailsResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetAgentResponse]() +## type [GetAgentResponse]() @@ -2111,7 +2269,7 @@ type GetAgentResponse struct { ``` -### func [ParseGetAgentResponse]() +### func [ParseGetAgentResponse]() ```go func ParseGetAgentResponse(rsp *http.Response) (*GetAgentResponse, error) @@ -2120,7 +2278,7 @@ func ParseGetAgentResponse(rsp *http.Response) (*GetAgentResponse, error) ParseGetAgentResponse parses an HTTP response from a GetAgentWithResponse call -### func \(GetAgentResponse\) [Status]() +### func \(GetAgentResponse\) [Status]() ```go func (r GetAgentResponse) Status() string @@ -2129,7 +2287,7 @@ func (r GetAgentResponse) Status() string Status returns HTTPResponse.Status -### func \(GetAgentResponse\) [StatusCode]() +### func \(GetAgentResponse\) [StatusCode]() ```go func (r GetAgentResponse) StatusCode() int @@ -2138,7 +2296,7 @@ func (r GetAgentResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetAuditExportResponse]() +## type [GetAuditExportResponse]() @@ -2154,7 +2312,7 @@ type GetAuditExportResponse struct { ``` -### func [ParseGetAuditExportResponse]() +### func [ParseGetAuditExportResponse]() ```go func ParseGetAuditExportResponse(rsp *http.Response) (*GetAuditExportResponse, error) @@ -2163,7 +2321,7 @@ func ParseGetAuditExportResponse(rsp *http.Response) (*GetAuditExportResponse, e ParseGetAuditExportResponse parses an HTTP response from a GetAuditExportWithResponse call -### func \(GetAuditExportResponse\) [Status]() +### func \(GetAuditExportResponse\) [Status]() ```go func (r GetAuditExportResponse) Status() string @@ -2172,7 +2330,7 @@ func (r GetAuditExportResponse) Status() string Status returns HTTPResponse.Status -### func \(GetAuditExportResponse\) [StatusCode]() +### func \(GetAuditExportResponse\) [StatusCode]() ```go func (r GetAuditExportResponse) StatusCode() int @@ -2181,7 +2339,7 @@ func (r GetAuditExportResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetAuditLogByIDResponse]() +## type [GetAuditLogByIDResponse]() @@ -2198,7 +2356,7 @@ type GetAuditLogByIDResponse struct { ``` -### func [ParseGetAuditLogByIDResponse]() +### func [ParseGetAuditLogByIDResponse]() ```go func ParseGetAuditLogByIDResponse(rsp *http.Response) (*GetAuditLogByIDResponse, error) @@ -2207,7 +2365,7 @@ func ParseGetAuditLogByIDResponse(rsp *http.Response) (*GetAuditLogByIDResponse, ParseGetAuditLogByIDResponse parses an HTTP response from a GetAuditLogByIDWithResponse call -### func \(GetAuditLogByIDResponse\) [Status]() +### func \(GetAuditLogByIDResponse\) [Status]() ```go func (r GetAuditLogByIDResponse) Status() string @@ -2216,7 +2374,7 @@ func (r GetAuditLogByIDResponse) Status() string Status returns HTTPResponse.Status -### func \(GetAuditLogByIDResponse\) [StatusCode]() +### func \(GetAuditLogByIDResponse\) [StatusCode]() ```go func (r GetAuditLogByIDResponse) StatusCode() int @@ -2225,7 +2383,7 @@ func (r GetAuditLogByIDResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetAuditLogsParams]() +## type [GetAuditLogsParams]() GetAuditLogsParams defines parameters for GetAuditLogs. @@ -2240,7 +2398,7 @@ type GetAuditLogsParams struct { ``` -## type [GetAuditLogsResponse]() +## type [GetAuditLogsResponse]() @@ -2257,7 +2415,7 @@ type GetAuditLogsResponse struct { ``` -### func [ParseGetAuditLogsResponse]() +### func [ParseGetAuditLogsResponse]() ```go func ParseGetAuditLogsResponse(rsp *http.Response) (*GetAuditLogsResponse, error) @@ -2266,7 +2424,7 @@ func ParseGetAuditLogsResponse(rsp *http.Response) (*GetAuditLogsResponse, error ParseGetAuditLogsResponse parses an HTTP response from a GetAuditLogsWithResponse call -### func \(GetAuditLogsResponse\) [Status]() +### func \(GetAuditLogsResponse\) [Status]() ```go func (r GetAuditLogsResponse) Status() string @@ -2275,7 +2433,7 @@ func (r GetAuditLogsResponse) Status() string Status returns HTTPResponse.Status -### func \(GetAuditLogsResponse\) [StatusCode]() +### func \(GetAuditLogsResponse\) [StatusCode]() ```go func (r GetAuditLogsResponse) StatusCode() int @@ -2284,7 +2442,7 @@ func (r GetAuditLogsResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetHealthReadyResponse]() +## type [GetHealthReadyResponse]() @@ -2298,7 +2456,7 @@ type GetHealthReadyResponse struct { ``` -### func [ParseGetHealthReadyResponse]() +### func [ParseGetHealthReadyResponse]() ```go func ParseGetHealthReadyResponse(rsp *http.Response) (*GetHealthReadyResponse, error) @@ -2307,7 +2465,7 @@ func ParseGetHealthReadyResponse(rsp *http.Response) (*GetHealthReadyResponse, e ParseGetHealthReadyResponse parses an HTTP response from a GetHealthReadyWithResponse call -### func \(GetHealthReadyResponse\) [Status]() +### func \(GetHealthReadyResponse\) [Status]() ```go func (r GetHealthReadyResponse) Status() string @@ -2316,7 +2474,7 @@ func (r GetHealthReadyResponse) Status() string Status returns HTTPResponse.Status -### func \(GetHealthReadyResponse\) [StatusCode]() +### func \(GetHealthReadyResponse\) [StatusCode]() ```go func (r GetHealthReadyResponse) StatusCode() int @@ -2325,7 +2483,7 @@ func (r GetHealthReadyResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetHealthResponse]() +## type [GetHealthResponse]() @@ -2338,7 +2496,7 @@ type GetHealthResponse struct { ``` -### func [ParseGetHealthResponse]() +### func [ParseGetHealthResponse]() ```go func ParseGetHealthResponse(rsp *http.Response) (*GetHealthResponse, error) @@ -2347,7 +2505,7 @@ func ParseGetHealthResponse(rsp *http.Response) (*GetHealthResponse, error) ParseGetHealthResponse parses an HTTP response from a GetHealthWithResponse call -### func \(GetHealthResponse\) [Status]() +### func \(GetHealthResponse\) [Status]() ```go func (r GetHealthResponse) Status() string @@ -2356,7 +2514,7 @@ func (r GetHealthResponse) Status() string Status returns HTTPResponse.Status -### func \(GetHealthResponse\) [StatusCode]() +### func \(GetHealthResponse\) [StatusCode]() ```go func (r GetHealthResponse) StatusCode() int @@ -2365,7 +2523,7 @@ func (r GetHealthResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetHealthStatusResponse]() +## type [GetHealthStatusResponse]() @@ -2381,7 +2539,7 @@ type GetHealthStatusResponse struct { ``` -### func [ParseGetHealthStatusResponse]() +### func [ParseGetHealthStatusResponse]() ```go func ParseGetHealthStatusResponse(rsp *http.Response) (*GetHealthStatusResponse, error) @@ -2390,7 +2548,7 @@ func ParseGetHealthStatusResponse(rsp *http.Response) (*GetHealthStatusResponse, ParseGetHealthStatusResponse parses an HTTP response from a GetHealthStatusWithResponse call -### func \(GetHealthStatusResponse\) [Status]() +### func \(GetHealthStatusResponse\) [Status]() ```go func (r GetHealthStatusResponse) Status() string @@ -2399,7 +2557,7 @@ func (r GetHealthStatusResponse) Status() string Status returns HTTPResponse.Status -### func \(GetHealthStatusResponse\) [StatusCode]() +### func \(GetHealthStatusResponse\) [StatusCode]() ```go func (r GetHealthStatusResponse) StatusCode() int @@ -2408,7 +2566,7 @@ func (r GetHealthStatusResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetJobByIDResponse]() +## type [GetJobByIDResponse]() @@ -2426,7 +2584,7 @@ type GetJobByIDResponse struct { ``` -### func [ParseGetJobByIDResponse]() +### func [ParseGetJobByIDResponse]() ```go func ParseGetJobByIDResponse(rsp *http.Response) (*GetJobByIDResponse, error) @@ -2435,7 +2593,7 @@ func ParseGetJobByIDResponse(rsp *http.Response) (*GetJobByIDResponse, error) ParseGetJobByIDResponse parses an HTTP response from a GetJobByIDWithResponse call -### func \(GetJobByIDResponse\) [Status]() +### func \(GetJobByIDResponse\) [Status]() ```go func (r GetJobByIDResponse) Status() string @@ -2444,7 +2602,7 @@ func (r GetJobByIDResponse) Status() string Status returns HTTPResponse.Status -### func \(GetJobByIDResponse\) [StatusCode]() +### func \(GetJobByIDResponse\) [StatusCode]() ```go func (r GetJobByIDResponse) StatusCode() int @@ -2453,7 +2611,7 @@ func (r GetJobByIDResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetJobParams]() +## type [GetJobParams]() GetJobParams defines parameters for GetJob. @@ -2471,7 +2629,7 @@ type GetJobParams struct { ``` -## type [GetJobParamsStatus]() +## type [GetJobParamsStatus]() GetJobParamsStatus defines parameters for GetJob. @@ -2492,7 +2650,7 @@ const ( ``` -## type [GetJobResponse]() +## type [GetJobResponse]() @@ -2509,7 +2667,7 @@ type GetJobResponse struct { ``` -### func [ParseGetJobResponse]() +### func [ParseGetJobResponse]() ```go func ParseGetJobResponse(rsp *http.Response) (*GetJobResponse, error) @@ -2518,7 +2676,7 @@ func ParseGetJobResponse(rsp *http.Response) (*GetJobResponse, error) ParseGetJobResponse parses an HTTP response from a GetJobWithResponse call -### func \(GetJobResponse\) [Status]() +### func \(GetJobResponse\) [Status]() ```go func (r GetJobResponse) Status() string @@ -2527,7 +2685,7 @@ func (r GetJobResponse) Status() string Status returns HTTPResponse.Status -### func \(GetJobResponse\) [StatusCode]() +### func \(GetJobResponse\) [StatusCode]() ```go func (r GetJobResponse) StatusCode() int @@ -2536,7 +2694,7 @@ func (r GetJobResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetJobStatusResponse]() +## type [GetJobStatusResponse]() @@ -2552,7 +2710,7 @@ type GetJobStatusResponse struct { ``` -### func [ParseGetJobStatusResponse]() +### func [ParseGetJobStatusResponse]() ```go func ParseGetJobStatusResponse(rsp *http.Response) (*GetJobStatusResponse, error) @@ -2561,7 +2719,7 @@ func ParseGetJobStatusResponse(rsp *http.Response) (*GetJobStatusResponse, error ParseGetJobStatusResponse parses an HTTP response from a GetJobStatusWithResponse call -### func \(GetJobStatusResponse\) [Status]() +### func \(GetJobStatusResponse\) [Status]() ```go func (r GetJobStatusResponse) Status() string @@ -2570,7 +2728,7 @@ func (r GetJobStatusResponse) Status() string Status returns HTTPResponse.Status -### func \(GetJobStatusResponse\) [StatusCode]() +### func \(GetJobStatusResponse\) [StatusCode]() ```go func (r GetJobStatusResponse) StatusCode() int @@ -2579,7 +2737,7 @@ func (r GetJobStatusResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeDiskResponse]() +## type [GetNodeDiskResponse]() @@ -2596,7 +2754,7 @@ type GetNodeDiskResponse struct { ``` -### func [ParseGetNodeDiskResponse]() +### func [ParseGetNodeDiskResponse]() ```go func ParseGetNodeDiskResponse(rsp *http.Response) (*GetNodeDiskResponse, error) @@ -2605,7 +2763,7 @@ func ParseGetNodeDiskResponse(rsp *http.Response) (*GetNodeDiskResponse, error) ParseGetNodeDiskResponse parses an HTTP response from a GetNodeDiskWithResponse call -### func \(GetNodeDiskResponse\) [Status]() +### func \(GetNodeDiskResponse\) [Status]() ```go func (r GetNodeDiskResponse) Status() string @@ -2614,7 +2772,7 @@ func (r GetNodeDiskResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeDiskResponse\) [StatusCode]() +### func \(GetNodeDiskResponse\) [StatusCode]() ```go func (r GetNodeDiskResponse) StatusCode() int @@ -2623,7 +2781,7 @@ func (r GetNodeDiskResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeHostnameResponse]() +## type [GetNodeHostnameResponse]() @@ -2640,7 +2798,7 @@ type GetNodeHostnameResponse struct { ``` -### func [ParseGetNodeHostnameResponse]() +### func [ParseGetNodeHostnameResponse]() ```go func ParseGetNodeHostnameResponse(rsp *http.Response) (*GetNodeHostnameResponse, error) @@ -2649,7 +2807,7 @@ func ParseGetNodeHostnameResponse(rsp *http.Response) (*GetNodeHostnameResponse, ParseGetNodeHostnameResponse parses an HTTP response from a GetNodeHostnameWithResponse call -### func \(GetNodeHostnameResponse\) [Status]() +### func \(GetNodeHostnameResponse\) [Status]() ```go func (r GetNodeHostnameResponse) Status() string @@ -2658,7 +2816,7 @@ func (r GetNodeHostnameResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeHostnameResponse\) [StatusCode]() +### func \(GetNodeHostnameResponse\) [StatusCode]() ```go func (r GetNodeHostnameResponse) StatusCode() int @@ -2667,7 +2825,7 @@ func (r GetNodeHostnameResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeLoadResponse]() +## type [GetNodeLoadResponse]() @@ -2684,7 +2842,7 @@ type GetNodeLoadResponse struct { ``` -### func [ParseGetNodeLoadResponse]() +### func [ParseGetNodeLoadResponse]() ```go func ParseGetNodeLoadResponse(rsp *http.Response) (*GetNodeLoadResponse, error) @@ -2693,7 +2851,7 @@ func ParseGetNodeLoadResponse(rsp *http.Response) (*GetNodeLoadResponse, error) ParseGetNodeLoadResponse parses an HTTP response from a GetNodeLoadWithResponse call -### func \(GetNodeLoadResponse\) [Status]() +### func \(GetNodeLoadResponse\) [Status]() ```go func (r GetNodeLoadResponse) Status() string @@ -2702,7 +2860,7 @@ func (r GetNodeLoadResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeLoadResponse\) [StatusCode]() +### func \(GetNodeLoadResponse\) [StatusCode]() ```go func (r GetNodeLoadResponse) StatusCode() int @@ -2711,7 +2869,7 @@ func (r GetNodeLoadResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeMemoryResponse]() +## type [GetNodeMemoryResponse]() @@ -2728,7 +2886,7 @@ type GetNodeMemoryResponse struct { ``` -### func [ParseGetNodeMemoryResponse]() +### func [ParseGetNodeMemoryResponse]() ```go func ParseGetNodeMemoryResponse(rsp *http.Response) (*GetNodeMemoryResponse, error) @@ -2737,7 +2895,7 @@ func ParseGetNodeMemoryResponse(rsp *http.Response) (*GetNodeMemoryResponse, err ParseGetNodeMemoryResponse parses an HTTP response from a GetNodeMemoryWithResponse call -### func \(GetNodeMemoryResponse\) [Status]() +### func \(GetNodeMemoryResponse\) [Status]() ```go func (r GetNodeMemoryResponse) Status() string @@ -2746,7 +2904,7 @@ func (r GetNodeMemoryResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeMemoryResponse\) [StatusCode]() +### func \(GetNodeMemoryResponse\) [StatusCode]() ```go func (r GetNodeMemoryResponse) StatusCode() int @@ -2755,7 +2913,7 @@ func (r GetNodeMemoryResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeNetworkDNSByInterfaceResponse]() +## type [GetNodeNetworkDNSByInterfaceResponse]() @@ -2772,7 +2930,7 @@ type GetNodeNetworkDNSByInterfaceResponse struct { ``` -### func [ParseGetNodeNetworkDNSByInterfaceResponse]() +### func [ParseGetNodeNetworkDNSByInterfaceResponse]() ```go func ParseGetNodeNetworkDNSByInterfaceResponse(rsp *http.Response) (*GetNodeNetworkDNSByInterfaceResponse, error) @@ -2781,7 +2939,7 @@ func ParseGetNodeNetworkDNSByInterfaceResponse(rsp *http.Response) (*GetNodeNetw ParseGetNodeNetworkDNSByInterfaceResponse parses an HTTP response from a GetNodeNetworkDNSByInterfaceWithResponse call -### func \(GetNodeNetworkDNSByInterfaceResponse\) [Status]() +### func \(GetNodeNetworkDNSByInterfaceResponse\) [Status]() ```go func (r GetNodeNetworkDNSByInterfaceResponse) Status() string @@ -2790,7 +2948,7 @@ func (r GetNodeNetworkDNSByInterfaceResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeNetworkDNSByInterfaceResponse\) [StatusCode]() +### func \(GetNodeNetworkDNSByInterfaceResponse\) [StatusCode]() ```go func (r GetNodeNetworkDNSByInterfaceResponse) StatusCode() int @@ -2799,7 +2957,7 @@ func (r GetNodeNetworkDNSByInterfaceResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeOSResponse]() +## type [GetNodeOSResponse]() @@ -2816,7 +2974,7 @@ type GetNodeOSResponse struct { ``` -### func [ParseGetNodeOSResponse]() +### func [ParseGetNodeOSResponse]() ```go func ParseGetNodeOSResponse(rsp *http.Response) (*GetNodeOSResponse, error) @@ -2825,7 +2983,7 @@ func ParseGetNodeOSResponse(rsp *http.Response) (*GetNodeOSResponse, error) ParseGetNodeOSResponse parses an HTTP response from a GetNodeOSWithResponse call -### func \(GetNodeOSResponse\) [Status]() +### func \(GetNodeOSResponse\) [Status]() ```go func (r GetNodeOSResponse) Status() string @@ -2834,7 +2992,7 @@ func (r GetNodeOSResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeOSResponse\) [StatusCode]() +### func \(GetNodeOSResponse\) [StatusCode]() ```go func (r GetNodeOSResponse) StatusCode() int @@ -2843,7 +3001,7 @@ func (r GetNodeOSResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeStatusResponse]() +## type [GetNodeStatusResponse]() @@ -2860,7 +3018,7 @@ type GetNodeStatusResponse struct { ``` -### func [ParseGetNodeStatusResponse]() +### func [ParseGetNodeStatusResponse]() ```go func ParseGetNodeStatusResponse(rsp *http.Response) (*GetNodeStatusResponse, error) @@ -2869,7 +3027,7 @@ func ParseGetNodeStatusResponse(rsp *http.Response) (*GetNodeStatusResponse, err ParseGetNodeStatusResponse parses an HTTP response from a GetNodeStatusWithResponse call -### func \(GetNodeStatusResponse\) [Status]() +### func \(GetNodeStatusResponse\) [Status]() ```go func (r GetNodeStatusResponse) Status() string @@ -2878,7 +3036,7 @@ func (r GetNodeStatusResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeStatusResponse\) [StatusCode]() +### func \(GetNodeStatusResponse\) [StatusCode]() ```go func (r GetNodeStatusResponse) StatusCode() int @@ -2887,7 +3045,7 @@ func (r GetNodeStatusResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetNodeUptimeResponse]() +## type [GetNodeUptimeResponse]() @@ -2904,7 +3062,7 @@ type GetNodeUptimeResponse struct { ``` -### func [ParseGetNodeUptimeResponse]() +### func [ParseGetNodeUptimeResponse]() ```go func ParseGetNodeUptimeResponse(rsp *http.Response) (*GetNodeUptimeResponse, error) @@ -2913,7 +3071,7 @@ func ParseGetNodeUptimeResponse(rsp *http.Response) (*GetNodeUptimeResponse, err ParseGetNodeUptimeResponse parses an HTTP response from a GetNodeUptimeWithResponse call -### func \(GetNodeUptimeResponse\) [Status]() +### func \(GetNodeUptimeResponse\) [Status]() ```go func (r GetNodeUptimeResponse) Status() string @@ -2922,7 +3080,7 @@ func (r GetNodeUptimeResponse) Status() string Status returns HTTPResponse.Status -### func \(GetNodeUptimeResponse\) [StatusCode]() +### func \(GetNodeUptimeResponse\) [StatusCode]() ```go func (r GetNodeUptimeResponse) StatusCode() int @@ -2931,7 +3089,7 @@ func (r GetNodeUptimeResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [GetVersionResponse]() +## type [GetVersionResponse]() @@ -2944,7 +3102,7 @@ type GetVersionResponse struct { ``` -### func [ParseGetVersionResponse]() +### func [ParseGetVersionResponse]() ```go func ParseGetVersionResponse(rsp *http.Response) (*GetVersionResponse, error) @@ -2953,7 +3111,7 @@ func ParseGetVersionResponse(rsp *http.Response) (*GetVersionResponse, error) ParseGetVersionResponse parses an HTTP response from a GetVersionWithResponse call -### func \(GetVersionResponse\) [Status]() +### func \(GetVersionResponse\) [Status]() ```go func (r GetVersionResponse) Status() string @@ -2962,7 +3120,7 @@ func (r GetVersionResponse) Status() string Status returns HTTPResponse.Status -### func \(GetVersionResponse\) [StatusCode]() +### func \(GetVersionResponse\) [StatusCode]() ```go func (r GetVersionResponse) StatusCode() int @@ -2971,7 +3129,7 @@ func (r GetVersionResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [HealthResponse]() +## type [HealthResponse]() HealthResponse defines model for HealthResponse. @@ -2983,7 +3141,7 @@ type HealthResponse struct { ``` -## type [Hostname]() +## type [Hostname]() Hostname defines model for Hostname. @@ -2992,7 +3150,7 @@ type Hostname = string ``` -## type [HostnameCollectionResponse]() +## type [HostnameCollectionResponse]() HostnameCollectionResponse defines model for HostnameCollectionResponse. @@ -3005,7 +3163,7 @@ type HostnameCollectionResponse struct { ``` -## type [HostnameResponse]() +## type [HostnameResponse]() HostnameResponse The hostname of the system. @@ -3023,7 +3181,7 @@ type HostnameResponse struct { ``` -## type [HttpRequestDoer]() +## type [HttpRequestDoer]() Doer performs HTTP requests. @@ -3036,7 +3194,7 @@ type HttpRequestDoer interface { ``` -## type [JobDetailResponse]() +## type [JobDetailResponse]() JobDetailResponse defines model for JobDetailResponse. @@ -3103,7 +3261,7 @@ type JobDetailResponse struct { ``` -## type [JobStats]() +## type [JobStats]() JobStats defines model for JobStats. @@ -3130,7 +3288,7 @@ type JobStats struct { ``` -## type [KVBucketInfo]() +## type [KVBucketInfo]() KVBucketInfo defines model for KVBucketInfo. @@ -3148,7 +3306,7 @@ type KVBucketInfo struct { ``` -## type [ListAgentsResponse]() +## type [ListAgentsResponse]() ListAgentsResponse defines model for ListAgentsResponse. @@ -3162,7 +3320,7 @@ type ListAgentsResponse struct { ``` -## type [ListAuditResponse]() +## type [ListAuditResponse]() ListAuditResponse defines model for ListAuditResponse. @@ -3177,7 +3335,7 @@ type ListAuditResponse struct { ``` -## type [ListJobsResponse]() +## type [ListJobsResponse]() ListJobsResponse defines model for ListJobsResponse. @@ -3191,7 +3349,7 @@ type ListJobsResponse struct { ``` -## type [LoadAverageResponse]() +## type [LoadAverageResponse]() LoadAverageResponse The system load averages for 1, 5, and 15 minutes. @@ -3209,7 +3367,7 @@ type LoadAverageResponse struct { ``` -## type [LoadCollectionResponse]() +## type [LoadCollectionResponse]() LoadCollectionResponse defines model for LoadCollectionResponse. @@ -3222,7 +3380,7 @@ type LoadCollectionResponse struct { ``` -## type [LoadResultItem]() +## type [LoadResultItem]() LoadResultItem defines model for LoadResultItem. @@ -3240,7 +3398,7 @@ type LoadResultItem struct { ``` -## type [MemoryCollectionResponse]() +## type [MemoryCollectionResponse]() MemoryCollectionResponse defines model for MemoryCollectionResponse. @@ -3253,7 +3411,7 @@ type MemoryCollectionResponse struct { ``` -## type [MemoryResponse]() +## type [MemoryResponse]() MemoryResponse Memory usage information. @@ -3271,7 +3429,7 @@ type MemoryResponse struct { ``` -## type [MemoryResultItem]() +## type [MemoryResultItem]() MemoryResultItem defines model for MemoryResultItem. @@ -3289,7 +3447,7 @@ type MemoryResultItem struct { ``` -## type [NATSInfo]() +## type [NATSInfo]() NATSInfo defines model for NATSInfo. @@ -3304,7 +3462,7 @@ type NATSInfo struct { ``` -## type [NetworkInterfaceResponse]() +## type [NetworkInterfaceResponse]() NetworkInterfaceResponse defines model for NetworkInterfaceResponse. @@ -3320,7 +3478,7 @@ type NetworkInterfaceResponse struct { ``` -## type [NetworkInterfaceResponseFamily]() +## type [NetworkInterfaceResponseFamily]() NetworkInterfaceResponseFamily IP address family. @@ -3338,8 +3496,41 @@ const ( ) ``` + +## type [NodeCondition]() + +NodeCondition defines model for NodeCondition. + +```go +type NodeCondition struct { + LastTransitionTime time.Time `json:"last_transition_time"` + Reason *string `json:"reason,omitempty"` + Status bool `json:"status"` + Type NodeConditionType `json:"type"` +} +``` + + +## type [NodeConditionType]() + +NodeConditionType defines model for NodeCondition.Type. + +```go +type NodeConditionType string +``` + +Defines values for NodeConditionType. + +```go +const ( + DiskPressure NodeConditionType = "DiskPressure" + HighLoad NodeConditionType = "HighLoad" + MemoryPressure NodeConditionType = "MemoryPressure" +) +``` + -## type [NodeStatusCollectionResponse]() +## type [NodeStatusCollectionResponse]() NodeStatusCollectionResponse defines model for NodeStatusCollectionResponse. @@ -3352,7 +3543,7 @@ type NodeStatusCollectionResponse struct { ``` -## type [NodeStatusResponse]() +## type [NodeStatusResponse]() NodeStatusResponse defines model for NodeStatusResponse. @@ -3382,7 +3573,7 @@ type NodeStatusResponse struct { ``` -## type [OSInfoCollectionResponse]() +## type [OSInfoCollectionResponse]() OSInfoCollectionResponse defines model for OSInfoCollectionResponse. @@ -3395,7 +3586,7 @@ type OSInfoCollectionResponse struct { ``` -## type [OSInfoResponse]() +## type [OSInfoResponse]() OSInfoResponse Operating system information. @@ -3410,7 +3601,7 @@ type OSInfoResponse struct { ``` -## type [OSInfoResultItem]() +## type [OSInfoResultItem]() OSInfoResultItem defines model for OSInfoResultItem. @@ -3428,7 +3619,7 @@ type OSInfoResultItem struct { ``` -## type [PingCollectionResponse]() +## type [PingCollectionResponse]() PingCollectionResponse defines model for PingCollectionResponse. @@ -3441,7 +3632,7 @@ type PingCollectionResponse struct { ``` -## type [PingResponse]() +## type [PingResponse]() PingResponse defines model for PingResponse. @@ -3474,7 +3665,7 @@ type PingResponse struct { ``` -## type [PostJobJSONRequestBody]() +## type [PostJobJSONRequestBody]() PostJobJSONRequestBody defines body for PostJob for application/json ContentType. @@ -3483,7 +3674,7 @@ type PostJobJSONRequestBody = CreateJobRequest ``` -## type [PostJobResponse]() +## type [PostJobResponse]() @@ -3500,7 +3691,7 @@ type PostJobResponse struct { ``` -### func [ParsePostJobResponse]() +### func [ParsePostJobResponse]() ```go func ParsePostJobResponse(rsp *http.Response) (*PostJobResponse, error) @@ -3509,7 +3700,7 @@ func ParsePostJobResponse(rsp *http.Response) (*PostJobResponse, error) ParsePostJobResponse parses an HTTP response from a PostJobWithResponse call -### func \(PostJobResponse\) [Status]() +### func \(PostJobResponse\) [Status]() ```go func (r PostJobResponse) Status() string @@ -3518,7 +3709,7 @@ func (r PostJobResponse) Status() string Status returns HTTPResponse.Status -### func \(PostJobResponse\) [StatusCode]() +### func \(PostJobResponse\) [StatusCode]() ```go func (r PostJobResponse) StatusCode() int @@ -3527,7 +3718,7 @@ func (r PostJobResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [PostNodeCommandExecJSONRequestBody]() +## type [PostNodeCommandExecJSONRequestBody]() PostNodeCommandExecJSONRequestBody defines body for PostNodeCommandExec for application/json ContentType. @@ -3536,7 +3727,7 @@ type PostNodeCommandExecJSONRequestBody = CommandExecRequest ``` -## type [PostNodeCommandExecResponse]() +## type [PostNodeCommandExecResponse]() @@ -3553,7 +3744,7 @@ type PostNodeCommandExecResponse struct { ``` -### func [ParsePostNodeCommandExecResponse]() +### func [ParsePostNodeCommandExecResponse]() ```go func ParsePostNodeCommandExecResponse(rsp *http.Response) (*PostNodeCommandExecResponse, error) @@ -3562,7 +3753,7 @@ func ParsePostNodeCommandExecResponse(rsp *http.Response) (*PostNodeCommandExecR ParsePostNodeCommandExecResponse parses an HTTP response from a PostNodeCommandExecWithResponse call -### func \(PostNodeCommandExecResponse\) [Status]() +### func \(PostNodeCommandExecResponse\) [Status]() ```go func (r PostNodeCommandExecResponse) Status() string @@ -3571,7 +3762,7 @@ func (r PostNodeCommandExecResponse) Status() string Status returns HTTPResponse.Status -### func \(PostNodeCommandExecResponse\) [StatusCode]() +### func \(PostNodeCommandExecResponse\) [StatusCode]() ```go func (r PostNodeCommandExecResponse) StatusCode() int @@ -3580,7 +3771,7 @@ func (r PostNodeCommandExecResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [PostNodeCommandShellJSONRequestBody]() +## type [PostNodeCommandShellJSONRequestBody]() PostNodeCommandShellJSONRequestBody defines body for PostNodeCommandShell for application/json ContentType. @@ -3589,7 +3780,7 @@ type PostNodeCommandShellJSONRequestBody = CommandShellRequest ``` -## type [PostNodeCommandShellResponse]() +## type [PostNodeCommandShellResponse]() @@ -3606,7 +3797,7 @@ type PostNodeCommandShellResponse struct { ``` -### func [ParsePostNodeCommandShellResponse]() +### func [ParsePostNodeCommandShellResponse]() ```go func ParsePostNodeCommandShellResponse(rsp *http.Response) (*PostNodeCommandShellResponse, error) @@ -3615,7 +3806,7 @@ func ParsePostNodeCommandShellResponse(rsp *http.Response) (*PostNodeCommandShel ParsePostNodeCommandShellResponse parses an HTTP response from a PostNodeCommandShellWithResponse call -### func \(PostNodeCommandShellResponse\) [Status]() +### func \(PostNodeCommandShellResponse\) [Status]() ```go func (r PostNodeCommandShellResponse) Status() string @@ -3624,7 +3815,7 @@ func (r PostNodeCommandShellResponse) Status() string Status returns HTTPResponse.Status -### func \(PostNodeCommandShellResponse\) [StatusCode]() +### func \(PostNodeCommandShellResponse\) [StatusCode]() ```go func (r PostNodeCommandShellResponse) StatusCode() int @@ -3633,7 +3824,7 @@ func (r PostNodeCommandShellResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [PostNodeNetworkPingJSONBody]() +## type [PostNodeNetworkPingJSONBody]() PostNodeNetworkPingJSONBody defines parameters for PostNodeNetworkPing. @@ -3645,7 +3836,7 @@ type PostNodeNetworkPingJSONBody struct { ``` -## type [PostNodeNetworkPingJSONRequestBody]() +## type [PostNodeNetworkPingJSONRequestBody]() PostNodeNetworkPingJSONRequestBody defines body for PostNodeNetworkPing for application/json ContentType. @@ -3654,7 +3845,7 @@ type PostNodeNetworkPingJSONRequestBody PostNodeNetworkPingJSONBody ``` -## type [PostNodeNetworkPingResponse]() +## type [PostNodeNetworkPingResponse]() @@ -3671,7 +3862,7 @@ type PostNodeNetworkPingResponse struct { ``` -### func [ParsePostNodeNetworkPingResponse]() +### func [ParsePostNodeNetworkPingResponse]() ```go func ParsePostNodeNetworkPingResponse(rsp *http.Response) (*PostNodeNetworkPingResponse, error) @@ -3680,7 +3871,7 @@ func ParsePostNodeNetworkPingResponse(rsp *http.Response) (*PostNodeNetworkPingR ParsePostNodeNetworkPingResponse parses an HTTP response from a PostNodeNetworkPingWithResponse call -### func \(PostNodeNetworkPingResponse\) [Status]() +### func \(PostNodeNetworkPingResponse\) [Status]() ```go func (r PostNodeNetworkPingResponse) Status() string @@ -3689,7 +3880,7 @@ func (r PostNodeNetworkPingResponse) Status() string Status returns HTTPResponse.Status -### func \(PostNodeNetworkPingResponse\) [StatusCode]() +### func \(PostNodeNetworkPingResponse\) [StatusCode]() ```go func (r PostNodeNetworkPingResponse) StatusCode() int @@ -3698,7 +3889,7 @@ func (r PostNodeNetworkPingResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [PutNodeNetworkDNSJSONRequestBody]() +## type [PutNodeNetworkDNSJSONRequestBody]() PutNodeNetworkDNSJSONRequestBody defines body for PutNodeNetworkDNS for application/json ContentType. @@ -3707,7 +3898,7 @@ type PutNodeNetworkDNSJSONRequestBody = DNSConfigUpdateRequest ``` -## type [PutNodeNetworkDNSResponse]() +## type [PutNodeNetworkDNSResponse]() @@ -3724,7 +3915,7 @@ type PutNodeNetworkDNSResponse struct { ``` -### func [ParsePutNodeNetworkDNSResponse]() +### func [ParsePutNodeNetworkDNSResponse]() ```go func ParsePutNodeNetworkDNSResponse(rsp *http.Response) (*PutNodeNetworkDNSResponse, error) @@ -3733,7 +3924,7 @@ func ParsePutNodeNetworkDNSResponse(rsp *http.Response) (*PutNodeNetworkDNSRespo ParsePutNodeNetworkDNSResponse parses an HTTP response from a PutNodeNetworkDNSWithResponse call -### func \(PutNodeNetworkDNSResponse\) [Status]() +### func \(PutNodeNetworkDNSResponse\) [Status]() ```go func (r PutNodeNetworkDNSResponse) Status() string @@ -3742,7 +3933,7 @@ func (r PutNodeNetworkDNSResponse) Status() string Status returns HTTPResponse.Status -### func \(PutNodeNetworkDNSResponse\) [StatusCode]() +### func \(PutNodeNetworkDNSResponse\) [StatusCode]() ```go func (r PutNodeNetworkDNSResponse) StatusCode() int @@ -3751,7 +3942,7 @@ func (r PutNodeNetworkDNSResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [QueueStatsResponse]() +## type [QueueStatsResponse]() QueueStatsResponse defines model for QueueStatsResponse. @@ -3772,7 +3963,7 @@ type QueueStatsResponse struct { ``` -## type [ReadyResponse]() +## type [ReadyResponse]() ReadyResponse defines model for ReadyResponse. @@ -3787,7 +3978,7 @@ type ReadyResponse struct { ``` -## type [RequestEditorFn]() +## type [RequestEditorFn]() RequestEditorFn is the function signature for the RequestEditor callback function @@ -3796,7 +3987,7 @@ type RequestEditorFn func(ctx context.Context, req *http.Request) error ``` -## type [RetryJobByIDJSONRequestBody]() +## type [RetryJobByIDJSONRequestBody]() RetryJobByIDJSONRequestBody defines body for RetryJobByID for application/json ContentType. @@ -3805,7 +3996,7 @@ type RetryJobByIDJSONRequestBody = RetryJobRequest ``` -## type [RetryJobByIDResponse]() +## type [RetryJobByIDResponse]() @@ -3823,7 +4014,7 @@ type RetryJobByIDResponse struct { ``` -### func [ParseRetryJobByIDResponse]() +### func [ParseRetryJobByIDResponse]() ```go func ParseRetryJobByIDResponse(rsp *http.Response) (*RetryJobByIDResponse, error) @@ -3832,7 +4023,7 @@ func ParseRetryJobByIDResponse(rsp *http.Response) (*RetryJobByIDResponse, error ParseRetryJobByIDResponse parses an HTTP response from a RetryJobByIDWithResponse call -### func \(RetryJobByIDResponse\) [Status]() +### func \(RetryJobByIDResponse\) [Status]() ```go func (r RetryJobByIDResponse) Status() string @@ -3841,7 +4032,7 @@ func (r RetryJobByIDResponse) Status() string Status returns HTTPResponse.Status -### func \(RetryJobByIDResponse\) [StatusCode]() +### func \(RetryJobByIDResponse\) [StatusCode]() ```go func (r RetryJobByIDResponse) StatusCode() int @@ -3850,7 +4041,7 @@ func (r RetryJobByIDResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [RetryJobRequest]() +## type [RetryJobRequest]() RetryJobRequest defines model for RetryJobRequest. @@ -3862,7 +4053,7 @@ type RetryJobRequest struct { ``` -## type [StatusResponse]() +## type [StatusResponse]() StatusResponse defines model for StatusResponse. @@ -3894,7 +4085,7 @@ type StatusResponse struct { ``` -## type [StreamInfo]() +## type [StreamInfo]() StreamInfo defines model for StreamInfo. @@ -3914,8 +4105,69 @@ type StreamInfo struct { } ``` + +## type [TimelineEvent]() + +TimelineEvent defines model for TimelineEvent. + +```go +type TimelineEvent struct { + Error *string `json:"error,omitempty"` + Event string `json:"event"` + Hostname *string `json:"hostname,omitempty"` + Message *string `json:"message,omitempty"` + Timestamp time.Time `json:"timestamp"` +} +``` + + +## type [UndrainAgentResponse]() + + + +```go +type UndrainAgentResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Message string `json:"message"` + } + JSON401 *ErrorResponse + JSON403 *ErrorResponse + JSON404 *ErrorResponse + JSON409 *ErrorResponse +} +``` + + +### func [ParseUndrainAgentResponse]() + +```go +func ParseUndrainAgentResponse(rsp *http.Response) (*UndrainAgentResponse, error) +``` + +ParseUndrainAgentResponse parses an HTTP response from a UndrainAgentWithResponse call + + +### func \(UndrainAgentResponse\) [Status]() + +```go +func (r UndrainAgentResponse) Status() string +``` + +Status returns HTTPResponse.Status + + +### func \(UndrainAgentResponse\) [StatusCode]() + +```go +func (r UndrainAgentResponse) StatusCode() int +``` + +StatusCode returns HTTPResponse.StatusCode + -## type [UptimeCollectionResponse]() +## type [UptimeCollectionResponse]() UptimeCollectionResponse defines model for UptimeCollectionResponse. @@ -3928,7 +4180,7 @@ type UptimeCollectionResponse struct { ``` -## type [UptimeResponse]() +## type [UptimeResponse]() UptimeResponse System uptime information. diff --git a/docs/gen/osapi.md b/docs/gen/osapi.md index 7597992..3b4dd2c 100644 --- a/docs/gen/osapi.md +++ b/docs/gen/osapi.md @@ -31,8 +31,10 @@ resp, err := client.Node.Exec(ctx, osapi.ExecRequest{ - [type AgentJobResponse](<#AgentJobResponse>) - [type AgentList](<#AgentList>) - [type AgentService](<#AgentService>) + - [func \(s \*AgentService\) Drain\(ctx context.Context, hostname string\) \(\*Response\[MessageResponse\], error\)](<#AgentService.Drain>) - [func \(s \*AgentService\) Get\(ctx context.Context, hostname string\) \(\*Response\[Agent\], error\)](<#AgentService.Get>) - [func \(s \*AgentService\) List\(ctx context.Context\) \(\*Response\[AgentList\], error\)](<#AgentService.List>) + - [func \(s \*AgentService\) Undrain\(ctx context.Context, hostname string\) \(\*Response\[MessageResponse\], error\)](<#AgentService.Undrain>) - [type AgentState](<#AgentState>) - [type AgentStats](<#AgentStats>) - [type AgentSummary](<#AgentSummary>) @@ -49,6 +51,9 @@ resp, err := client.Node.Exec(ctx, osapi.ExecRequest{ - [type Collection](<#Collection>) - [type CommandResult](<#CommandResult>) - [type ComponentHealth](<#ComponentHealth>) +- [type Condition](<#Condition>) +- [type ConflictError](<#ConflictError>) + - [func \(e \*ConflictError\) Unwrap\(\) error](<#ConflictError.Unwrap>) - [type ConsumerDetail](<#ConsumerDetail>) - [type ConsumerStats](<#ConsumerStats>) - [type DNSConfig](<#DNSConfig>) @@ -79,6 +84,7 @@ resp, err := client.Node.Exec(ctx, osapi.ExecRequest{ - [type LoadResult](<#LoadResult>) - [type Memory](<#Memory>) - [type MemoryResult](<#MemoryResult>) +- [type MessageResponse](<#MessageResponse>) - [type MetricsService](<#MetricsService>) - [func \(s \*MetricsService\) Get\(ctx context.Context\) \(string, error\)](<#MetricsService.Get>) - [type NATSInfo](<#NATSInfo>) @@ -145,7 +151,7 @@ func (e *APIError) Error() string Error returns a formatted error string. -## type [Agent]() +## type [Agent]() Agent represents a registered OSAPI agent. @@ -153,6 +159,7 @@ Agent represents a registered OSAPI agent. type Agent struct { Hostname string Status string + State string Labels map[string]string Architecture string CPUCount int @@ -164,6 +171,8 @@ type Agent struct { Memory *Memory OSInfo *OSInfo Interfaces []NetworkInterface + Conditions []Condition + Timeline []TimelineEvent Uptime string StartedAt time.Time RegisteredAt time.Time @@ -186,7 +195,7 @@ type AgentJobResponse struct { ``` -## type [AgentList]() +## type [AgentList]() AgentList is a collection of agents. @@ -198,7 +207,7 @@ type AgentList struct { ``` -## type [AgentService]() +## type [AgentService]() AgentService provides agent discovery and details operations. @@ -208,8 +217,17 @@ type AgentService struct { } ``` + +### func \(\*AgentService\) [Drain]() + +```go +func (s *AgentService) Drain(ctx context.Context, hostname string) (*Response[MessageResponse], error) +``` + +Drain initiates draining of an agent, stopping it from accepting new jobs while allowing in\-flight jobs to complete. + -### func \(\*AgentService\) [Get]() +### func \(\*AgentService\) [Get]() ```go func (s *AgentService) Get(ctx context.Context, hostname string) (*Response[Agent], error) @@ -218,7 +236,7 @@ func (s *AgentService) Get(ctx context.Context, hostname string) (*Response[Agen Get retrieves detailed information about a specific agent by hostname. -### func \(\*AgentService\) [List]() +### func \(\*AgentService\) [List]() ```go func (s *AgentService) List(ctx context.Context) (*Response[AgentList], error) @@ -226,6 +244,15 @@ func (s *AgentService) List(ctx context.Context) (*Response[AgentList], error) List retrieves all active agents. + +### func \(\*AgentService\) [Undrain]() + +```go +func (s *AgentService) Undrain(ctx context.Context, hostname string) (*Response[MessageResponse], error) +``` + +Undrain resumes job acceptance on a drained agent. + ## type [AgentState]() @@ -434,6 +461,40 @@ type ComponentHealth struct { } ``` + +## type [Condition]() + +Condition represents a node condition evaluated agent\-side. + +```go +type Condition struct { + Type string + Status bool + Reason string + LastTransitionTime time.Time +} +``` + + +## type [ConflictError]() + +ConflictError represents conflict errors \(409\). + +```go +type ConflictError struct { + APIError +} +``` + + +### func \(\*ConflictError\) [Unwrap]() + +```go +func (e *ConflictError) Unwrap() error +``` + +Unwrap returns the underlying APIError. + ## type [ConsumerDetail]() @@ -638,7 +699,7 @@ type JobDetail struct { ``` -## type [JobList]() +## type [JobList]() JobList is a paginated list of jobs. @@ -763,7 +824,7 @@ type ListParams struct { ``` -## type [LoadAverage]() +## type [LoadAverage]() LoadAverage represents system load averages. @@ -789,7 +850,7 @@ type LoadResult struct { ``` -## type [Memory]() +## type [Memory]() Memory represents memory usage information. @@ -814,6 +875,17 @@ type MemoryResult struct { } ``` + +## type [MessageResponse]() + +MessageResponse represents a simple message response from the API. + +```go +type MessageResponse struct { + Message string +} +``` + ## type [MetricsService]() @@ -847,7 +919,7 @@ type NATSInfo struct { ``` -## type [NetworkInterface]() +## type [NetworkInterface]() NetworkInterface represents a network interface on an agent. @@ -1018,7 +1090,7 @@ func (e *NotFoundError) Unwrap() error Unwrap returns the underlying APIError. -## type [OSInfo]() +## type [OSInfo]() OSInfo represents operating system information. @@ -1088,7 +1160,7 @@ type PingResult struct { ``` -## type [QueueStats]() +## type [QueueStats]() QueueStats represents job queue statistics. @@ -1222,9 +1294,9 @@ type SystemStatus struct { ``` -## type [TimelineEvent]() +## type [TimelineEvent]() -TimelineEvent represents a job lifecycle event. +TimelineEvent represents a lifecycle event. Used by both job timelines and agent state transition history. ```go type TimelineEvent struct { @@ -1237,7 +1309,7 @@ type TimelineEvent struct { ``` -## type [UnexpectedStatusError]() +## type [UnexpectedStatusError]() UnexpectedStatusError represents unexpected HTTP status codes. @@ -1248,7 +1320,7 @@ type UnexpectedStatusError struct { ``` -### func \(\*UnexpectedStatusError\) [Unwrap]() +### func \(\*UnexpectedStatusError\) [Unwrap]() ```go func (e *UnexpectedStatusError) Unwrap() error diff --git a/pkg/osapi/agent.go b/pkg/osapi/agent.go index ff2329d..bcec134 100644 --- a/pkg/osapi/agent.go +++ b/pkg/osapi/agent.go @@ -27,6 +27,11 @@ import ( "github.com/osapi-io/osapi-sdk/pkg/osapi/gen" ) +// MessageResponse represents a simple message response from the API. +type MessageResponse struct { + Message string +} + // AgentService provides agent discovery and details operations. type AgentService struct { client *gen.ClientWithResponses @@ -78,3 +83,60 @@ func (s *AgentService) Get( return NewResponse(agentFromGen(resp.JSON200), resp.Body), nil } + +// Drain initiates draining of an agent, stopping it from accepting +// new jobs while allowing in-flight jobs to complete. +func (s *AgentService) Drain( + ctx context.Context, + hostname string, +) (*Response[MessageResponse], error) { + resp, err := s.client.DrainAgentWithResponse(ctx, hostname) + if err != nil { + return nil, fmt.Errorf("drain agent %s: %w", hostname, err) + } + + if err := checkError(resp.StatusCode(), resp.JSON401, resp.JSON403, resp.JSON404, resp.JSON409); err != nil { + return nil, err + } + + if resp.JSON200 == nil { + return nil, &UnexpectedStatusError{APIError{ + StatusCode: resp.StatusCode(), + Message: "nil response body", + }} + } + + msg := MessageResponse{ + Message: resp.JSON200.Message, + } + + return NewResponse(msg, resp.Body), nil +} + +// Undrain resumes job acceptance on a drained agent. +func (s *AgentService) Undrain( + ctx context.Context, + hostname string, +) (*Response[MessageResponse], error) { + resp, err := s.client.UndrainAgentWithResponse(ctx, hostname) + if err != nil { + return nil, fmt.Errorf("undrain agent %s: %w", hostname, err) + } + + if err := checkError(resp.StatusCode(), resp.JSON401, resp.JSON403, resp.JSON404, resp.JSON409); err != nil { + return nil, err + } + + if resp.JSON200 == nil { + return nil, &UnexpectedStatusError{APIError{ + StatusCode: resp.StatusCode(), + Message: "nil response body", + }} + } + + msg := MessageResponse{ + Message: resp.JSON200.Message, + } + + return NewResponse(msg, resp.Body), nil +} diff --git a/pkg/osapi/agent_public_test.go b/pkg/osapi/agent_public_test.go index 0ecbef6..cdeaccd 100644 --- a/pkg/osapi/agent_public_test.go +++ b/pkg/osapi/agent_public_test.go @@ -46,10 +46,17 @@ func (suite *AgentPublicTestSuite) SetupTest() { func (suite *AgentPublicTestSuite) TestList() { tests := []struct { name string + handler http.HandlerFunc + serverURL string validateFunc func(*osapi.Response[osapi.AgentList], error) }{ { name: "when requesting agents returns no error", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"agents":[],"total":0}`)) + }, validateFunc: func(resp *osapi.Response[osapi.AgentList], err error) { suite.NoError(err) suite.NotNil(resp) @@ -57,21 +64,60 @@ func (suite *AgentPublicTestSuite) TestList() { suite.Empty(resp.Data.Agents) }, }, + { + name: "when server returns 401 returns AuthError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.AgentList], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.AuthError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusUnauthorized, target.StatusCode) + }, + }, + { + name: "when client HTTP error returns wrapped error", + serverURL: "http://127.0.0.1:0", + validateFunc: func(resp *osapi.Response[osapi.AgentList], err error) { + suite.Error(err) + suite.Nil(resp) + suite.Contains(err.Error(), "list agents") + }, + }, + { + name: "when response JSON200 is nil returns UnexpectedStatusError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + }, + validateFunc: func(resp *osapi.Response[osapi.AgentList], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.UnexpectedStatusError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusOK, target.StatusCode) + suite.Contains(target.Message, "nil response body") + }, + }, } for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"agents":[],"total":0}`)) - }), - ) - defer server.Close() + url := tc.serverURL + if tc.handler != nil { + server := httptest.NewServer(tc.handler) + defer server.Close() + url = server.URL + } sut := osapi.New( - server.URL, + url, "test-token", osapi.WithLogger(slog.Default()), ) @@ -82,53 +128,65 @@ func (suite *AgentPublicTestSuite) TestList() { } } -func (suite *AgentPublicTestSuite) TestListError() { +func (suite *AgentPublicTestSuite) TestGet() { tests := []struct { name string + handler http.HandlerFunc serverURL string - serverFunc func() *httptest.Server - validateFunc func(*osapi.Response[osapi.AgentList], error) + hostname string + validateFunc func(*osapi.Response[osapi.Agent], error) }{ { - name: "when server returns 401 returns AuthError", - serverFunc: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) - }), - ) + name: "when requesting agent details returns no error", + hostname: "server1", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"hostname":"server1","status":"Ready"}`)) }, - validateFunc: func(resp *osapi.Response[osapi.AgentList], err error) { + validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { + suite.NoError(err) + suite.NotNil(resp) + suite.Equal("server1", resp.Data.Hostname) + suite.Equal("Ready", resp.Data.Status) + }, + }, + { + name: "when server returns 404 returns NotFoundError", + hostname: "unknown-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"error":"agent not found"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { suite.Error(err) suite.Nil(resp) - var target *osapi.AuthError + var target *osapi.NotFoundError suite.True(errors.As(err, &target)) - suite.Equal(http.StatusUnauthorized, target.StatusCode) + suite.Equal(http.StatusNotFound, target.StatusCode) + suite.Equal("agent not found", target.Message) }, }, { name: "when client HTTP error returns wrapped error", + hostname: "unknown-host", serverURL: "http://127.0.0.1:0", - validateFunc: func(resp *osapi.Response[osapi.AgentList], err error) { + validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { suite.Error(err) suite.Nil(resp) - suite.Contains(err.Error(), "list agents") + suite.Contains(err.Error(), "get agent") }, }, { - name: "when response JSON200 is nil returns UnexpectedStatusError", - serverFunc: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - }), - ) + name: "when response JSON200 is nil returns UnexpectedStatusError", + hostname: "unknown-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) }, - validateFunc: func(resp *osapi.Response[osapi.AgentList], err error) { + validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { suite.Error(err) suite.Nil(resp) @@ -143,8 +201,8 @@ func (suite *AgentPublicTestSuite) TestListError() { for _, tc := range tests { suite.Run(tc.name, func() { url := tc.serverURL - if tc.serverFunc != nil { - server := tc.serverFunc() + if tc.handler != nil { + server := httptest.NewServer(tc.handler) defer server.Close() url = server.URL } @@ -155,101 +213,194 @@ func (suite *AgentPublicTestSuite) TestListError() { osapi.WithLogger(slog.Default()), ) - resp, err := sut.Agent.List(suite.ctx) + resp, err := sut.Agent.Get(suite.ctx, tc.hostname) tc.validateFunc(resp, err) }) } } -func (suite *AgentPublicTestSuite) TestGet() { +func (suite *AgentPublicTestSuite) TestDrain() { tests := []struct { name string + handler http.HandlerFunc + serverURL string hostname string - validateFunc func(*osapi.Response[osapi.Agent], error) + validateFunc func(*osapi.Response[osapi.MessageResponse], error) }{ { - name: "when requesting agent details returns no error", + name: "when draining agent returns success", hostname: "server1", - validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"message":"drain initiated for agent server1"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { suite.NoError(err) suite.NotNil(resp) - suite.Equal("server1", resp.Data.Hostname) - suite.Equal("Ready", resp.Data.Status) + suite.Equal("drain initiated for agent server1", resp.Data.Message) + }, + }, + { + name: "when server returns 409 returns ConflictError", + hostname: "test-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusConflict) + _, _ = w.Write([]byte(`{"error":"agent already draining"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.ConflictError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusConflict, target.StatusCode) + suite.Equal("agent already draining", target.Message) + }, + }, + { + name: "when server returns 404 returns NotFoundError", + hostname: "test-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"error":"agent not found"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.NotFoundError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusNotFound, target.StatusCode) + }, + }, + { + name: "when client HTTP error returns wrapped error", + hostname: "test-host", + serverURL: "http://127.0.0.1:0", + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { + suite.Error(err) + suite.Nil(resp) + suite.Contains(err.Error(), "drain agent") + }, + }, + { + name: "when response JSON200 is nil returns UnexpectedStatusError", + hostname: "test-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + }, + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.UnexpectedStatusError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusOK, target.StatusCode) + suite.Contains(target.Message, "nil response body") }, }, } for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"hostname":"server1","status":"Ready"}`)) - }), - ) - defer server.Close() + url := tc.serverURL + if tc.handler != nil { + server := httptest.NewServer(tc.handler) + defer server.Close() + url = server.URL + } sut := osapi.New( - server.URL, + url, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Agent.Get(suite.ctx, tc.hostname) + resp, err := sut.Agent.Drain(suite.ctx, tc.hostname) tc.validateFunc(resp, err) }) } } -func (suite *AgentPublicTestSuite) TestGetError() { +func (suite *AgentPublicTestSuite) TestUndrain() { tests := []struct { name string + handler http.HandlerFunc serverURL string - serverFunc func() *httptest.Server - validateFunc func(*osapi.Response[osapi.Agent], error) + hostname string + validateFunc func(*osapi.Response[osapi.MessageResponse], error) }{ { - name: "when server returns 404 returns NotFoundError", - serverFunc: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"error":"agent not found"}`)) - }), - ) + name: "when undraining agent returns success", + hostname: "server1", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"message":"undrain initiated for agent server1"}`)) }, - validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { + suite.NoError(err) + suite.NotNil(resp) + suite.Equal("undrain initiated for agent server1", resp.Data.Message) + }, + }, + { + name: "when server returns 409 returns ConflictError", + hostname: "test-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusConflict) + _, _ = w.Write([]byte(`{"error":"agent not in draining state"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.ConflictError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusConflict, target.StatusCode) + suite.Equal("agent not in draining state", target.Message) + }, + }, + { + name: "when server returns 404 returns NotFoundError", + hostname: "test-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"error":"agent not found"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { suite.Error(err) suite.Nil(resp) var target *osapi.NotFoundError suite.True(errors.As(err, &target)) suite.Equal(http.StatusNotFound, target.StatusCode) - suite.Equal("agent not found", target.Message) }, }, { name: "when client HTTP error returns wrapped error", + hostname: "test-host", serverURL: "http://127.0.0.1:0", - validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { suite.Error(err) suite.Nil(resp) - suite.Contains(err.Error(), "get agent") + suite.Contains(err.Error(), "undrain agent") }, }, { - name: "when response JSON200 is nil returns UnexpectedStatusError", - serverFunc: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - }), - ) + name: "when response JSON200 is nil returns UnexpectedStatusError", + hostname: "test-host", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) }, - validateFunc: func(resp *osapi.Response[osapi.Agent], err error) { + validateFunc: func(resp *osapi.Response[osapi.MessageResponse], err error) { suite.Error(err) suite.Nil(resp) @@ -264,8 +415,8 @@ func (suite *AgentPublicTestSuite) TestGetError() { for _, tc := range tests { suite.Run(tc.name, func() { url := tc.serverURL - if tc.serverFunc != nil { - server := tc.serverFunc() + if tc.handler != nil { + server := httptest.NewServer(tc.handler) defer server.Close() url = server.URL } @@ -276,7 +427,7 @@ func (suite *AgentPublicTestSuite) TestGetError() { osapi.WithLogger(slog.Default()), ) - resp, err := sut.Agent.Get(suite.ctx, "unknown-host") + resp, err := sut.Agent.Undrain(suite.ctx, tc.hostname) tc.validateFunc(resp, err) }) } diff --git a/pkg/osapi/agent_types.go b/pkg/osapi/agent_types.go index bfb14d7..ee942fa 100644 --- a/pkg/osapi/agent_types.go +++ b/pkg/osapi/agent_types.go @@ -30,6 +30,7 @@ import ( type Agent struct { Hostname string Status string + State string Labels map[string]string Architecture string CPUCount int @@ -41,12 +42,22 @@ type Agent struct { Memory *Memory OSInfo *OSInfo Interfaces []NetworkInterface + Conditions []Condition + Timeline []TimelineEvent Uptime string StartedAt time.Time RegisteredAt time.Time Facts map[string]any } +// Condition represents a node condition evaluated agent-side. +type Condition struct { + Type string + Status bool + Reason string + LastTransitionTime time.Time +} + // AgentList is a collection of agents. type AgentList struct { Agents []Agent @@ -168,6 +179,55 @@ func agentFromGen( a.Facts = *g.Facts } + if g.State != nil { + a.State = string(*g.State) + } + + if g.Conditions != nil { + conditions := make([]Condition, 0, len(*g.Conditions)) + for _, c := range *g.Conditions { + cond := Condition{ + Type: string(c.Type), + Status: c.Status, + LastTransitionTime: c.LastTransitionTime, + } + + if c.Reason != nil { + cond.Reason = *c.Reason + } + + conditions = append(conditions, cond) + } + + a.Conditions = conditions + } + + if g.Timeline != nil { + timeline := make([]TimelineEvent, 0, len(*g.Timeline)) + for _, t := range *g.Timeline { + te := TimelineEvent{ + Event: t.Event, + Timestamp: t.Timestamp.Format(time.RFC3339), + } + + if t.Hostname != nil { + te.Hostname = *t.Hostname + } + + if t.Message != nil { + te.Message = *t.Message + } + + if t.Error != nil { + te.Error = *t.Error + } + + timeline = append(timeline, te) + } + + a.Timeline = timeline + } + return a } diff --git a/pkg/osapi/agent_types_test.go b/pkg/osapi/agent_types_test.go index 7414b31..df424f9 100644 --- a/pkg/osapi/agent_types_test.go +++ b/pkg/osapi/agent_types_test.go @@ -58,6 +58,12 @@ func (suite *AgentTypesTestSuite) TestAgentFromGen() { ipv6 := "fe80::1" mac := "00:11:22:33:44:55" facts := map[string]interface{}{"custom_key": "custom_value"} + state := gen.AgentInfoStateReady + reason := "load avg 0.50 < 4.00" + condTime := now.Add(-30 * time.Minute) + hostname := "web-01" + message := "agent started" + errMsg := "connection lost" return &gen.AgentInfo{ Hostname: "web-01", @@ -96,11 +102,35 @@ func (suite *AgentTypesTestSuite) TestAgentFromGen() { StartedAt: &startedAt, RegisteredAt: &now, Facts: &facts, + State: &state, + Conditions: &[]gen.NodeCondition{ + { + Type: gen.HighLoad, + Status: false, + Reason: &reason, + LastTransitionTime: condTime, + }, + }, + Timeline: &[]gen.TimelineEvent{ + { + Timestamp: startedAt, + Event: "AgentStarted", + Hostname: &hostname, + Message: &message, + }, + { + Timestamp: now, + Event: "AgentFailed", + Hostname: &hostname, + Error: &errMsg, + }, + }, } }(), validateFunc: func(a Agent) { suite.Equal("web-01", a.Hostname) suite.Equal("Ready", a.Status) + suite.Equal("Ready", a.State) suite.Equal(map[string]string{"group": "web", "env": "prod"}, a.Labels) suite.Equal("amd64", a.Architecture) suite.Equal(8, a.CPUCount) @@ -134,6 +164,28 @@ func (suite *AgentTypesTestSuite) TestAgentFromGen() { suite.Equal(startedAt, a.StartedAt) suite.Equal(now, a.RegisteredAt) suite.Equal(map[string]any{"custom_key": "custom_value"}, a.Facts) + + suite.Require().Len(a.Conditions, 1) + suite.Equal("HighLoad", a.Conditions[0].Type) + suite.False(a.Conditions[0].Status) + suite.Equal("load avg 0.50 < 4.00", a.Conditions[0].Reason) + suite.Equal( + now.Add(-30*time.Minute), + a.Conditions[0].LastTransitionTime, + ) + + suite.Require().Len(a.Timeline, 2) + suite.Equal("AgentStarted", a.Timeline[0].Event) + suite.Equal(startedAt.Format(time.RFC3339), a.Timeline[0].Timestamp) + suite.Equal("web-01", a.Timeline[0].Hostname) + suite.Equal("agent started", a.Timeline[0].Message) + suite.Empty(a.Timeline[0].Error) + + suite.Equal("AgentFailed", a.Timeline[1].Event) + suite.Equal(now.Format(time.RFC3339), a.Timeline[1].Timestamp) + suite.Equal("web-01", a.Timeline[1].Hostname) + suite.Empty(a.Timeline[1].Message) + suite.Equal("connection lost", a.Timeline[1].Error) }, }, { @@ -145,6 +197,7 @@ func (suite *AgentTypesTestSuite) TestAgentFromGen() { validateFunc: func(a Agent) { suite.Equal("minimal-host", a.Hostname) suite.Equal("Ready", a.Status) + suite.Empty(a.State) suite.Nil(a.Labels) suite.Empty(a.Architecture) suite.Zero(a.CPUCount) @@ -156,6 +209,8 @@ func (suite *AgentTypesTestSuite) TestAgentFromGen() { suite.Nil(a.Memory) suite.Nil(a.OSInfo) suite.Nil(a.Interfaces) + suite.Nil(a.Conditions) + suite.Nil(a.Timeline) suite.Empty(a.Uptime) suite.True(a.StartedAt.IsZero()) suite.True(a.RegisteredAt.IsZero()) diff --git a/pkg/osapi/audit_public_test.go b/pkg/osapi/audit_public_test.go index 96adadd..7cb8735 100644 --- a/pkg/osapi/audit_public_test.go +++ b/pkg/osapi/audit_public_test.go @@ -46,6 +46,8 @@ func (suite *AuditPublicTestSuite) SetupTest() { func (suite *AuditPublicTestSuite) TestList() { tests := []struct { name string + handler http.HandlerFunc + serverURL string limit int offset int validateFunc func(*osapi.Response[osapi.AuditList], error) @@ -54,6 +56,11 @@ func (suite *AuditPublicTestSuite) TestList() { name: "when listing audit entries returns audit list", limit: 20, offset: 0, + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"items":[],"total_items":0}`)) + }), validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.NoError(err) suite.NotNil(resp) @@ -61,48 +68,15 @@ func (suite *AuditPublicTestSuite) TestList() { suite.Empty(resp.Data.Items) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"items":[],"total_items":0}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Audit.List(suite.ctx, tc.limit, tc.offset) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *AuditPublicTestSuite) TestListError() { - tests := []struct { - name string - setupServer func() *httptest.Server - validateFunc func(*osapi.Response[osapi.AuditList], error) - }{ { - name: "when server returns 401 returns AuthError", - setupServer: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) - }), - ) - }, + name: "when server returns 401 returns AuthError", + limit: 20, + offset: 0, + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) + }), validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.Error(err) suite.Nil(resp) @@ -113,15 +87,10 @@ func (suite *AuditPublicTestSuite) TestListError() { }, }, { - name: "when HTTP request fails returns error", - setupServer: func() *httptest.Server { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - return server - }, + name: "when client HTTP request fails returns error", + limit: 20, + offset: 0, + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.Error(err) suite.Nil(resp) @@ -129,15 +98,13 @@ func (suite *AuditPublicTestSuite) TestListError() { }, }, { - name: "when response body is nil returns UnexpectedStatusError", - setupServer: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - }), - ) - }, + name: "when response body is nil returns UnexpectedStatusError", + limit: 20, + offset: 0, + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + }), validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.Error(err) suite.Nil(resp) @@ -152,16 +119,20 @@ func (suite *AuditPublicTestSuite) TestListError() { for _, tc := range tests { suite.Run(tc.name, func() { - server := tc.setupServer() - defer server.Close() + serverURL := tc.serverURL + if tc.handler != nil { + server := httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Audit.List(suite.ctx, 20, 0) + resp, err := sut.Audit.List(suite.ctx, tc.limit, tc.offset) tc.validateFunc(resp, err) }) } @@ -170,12 +141,23 @@ func (suite *AuditPublicTestSuite) TestListError() { func (suite *AuditPublicTestSuite) TestGet() { tests := []struct { name string + handler http.HandlerFunc + serverURL string id string validateFunc func(*osapi.Response[osapi.AuditEntry], error) }{ { name: "when valid UUID returns audit entry", id: "550e8400-e29b-41d4-a716-446655440000", + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte( + `{"entry":{"id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2026-01-01T00:00:00Z","user":"admin","roles":["admin"],"method":"GET","path":"/api/v1/health","response_code":200,"duration_ms":5,"source_ip":"127.0.0.1"}}`, + ), + ) + }), validateFunc: func(resp *osapi.Response[osapi.AuditEntry], err error) { suite.NoError(err) suite.NotNil(resp) @@ -188,57 +170,28 @@ func (suite *AuditPublicTestSuite) TestGet() { { name: "when invalid UUID returns error", id: "not-a-uuid", + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte( + `{"entry":{"id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2026-01-01T00:00:00Z","user":"admin","roles":["admin"],"method":"GET","path":"/api/v1/health","response_code":200,"duration_ms":5,"source_ip":"127.0.0.1"}}`, + ), + ) + }), validateFunc: func(resp *osapi.Response[osapi.AuditEntry], err error) { suite.Error(err) suite.Nil(resp) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write( - []byte( - `{"entry":{"id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2026-01-01T00:00:00Z","user":"admin","roles":["admin"],"method":"GET","path":"/api/v1/health","response_code":200,"duration_ms":5,"source_ip":"127.0.0.1"}}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Audit.Get(suite.ctx, tc.id) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *AuditPublicTestSuite) TestGetError() { - tests := []struct { - name string - setupServer func() *httptest.Server - validateFunc func(*osapi.Response[osapi.AuditEntry], error) - }{ { name: "when server returns 404 returns NotFoundError", - setupServer: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"error":"audit entry not found"}`)) - }), - ) - }, + id: "550e8400-e29b-41d4-a716-446655440000", + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"error":"audit entry not found"}`)) + }), validateFunc: func(resp *osapi.Response[osapi.AuditEntry], err error) { suite.Error(err) suite.Nil(resp) @@ -249,15 +202,9 @@ func (suite *AuditPublicTestSuite) TestGetError() { }, }, { - name: "when HTTP request fails returns error", - setupServer: func() *httptest.Server { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - return server - }, + name: "when client HTTP request fails returns error", + id: "550e8400-e29b-41d4-a716-446655440000", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.AuditEntry], err error) { suite.Error(err) suite.Nil(resp) @@ -266,14 +213,11 @@ func (suite *AuditPublicTestSuite) TestGetError() { }, { name: "when response body is nil returns UnexpectedStatusError", - setupServer: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - }), - ) - }, + id: "550e8400-e29b-41d4-a716-446655440000", + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + }), validateFunc: func(resp *osapi.Response[osapi.AuditEntry], err error) { suite.Error(err) suite.Nil(resp) @@ -288,16 +232,20 @@ func (suite *AuditPublicTestSuite) TestGetError() { for _, tc := range tests { suite.Run(tc.name, func() { - server := tc.setupServer() - defer server.Close() + serverURL := tc.serverURL + if tc.handler != nil { + server := httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Audit.Get(suite.ctx, "550e8400-e29b-41d4-a716-446655440000") + resp, err := sut.Audit.Get(suite.ctx, tc.id) tc.validateFunc(resp, err) }) } @@ -306,10 +254,17 @@ func (suite *AuditPublicTestSuite) TestGetError() { func (suite *AuditPublicTestSuite) TestExport() { tests := []struct { name string + handler http.HandlerFunc + serverURL string validateFunc func(*osapi.Response[osapi.AuditList], error) }{ { name: "when exporting audit entries returns audit list", + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"items":[],"total_items":0}`)) + }), validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.NoError(err) suite.NotNil(resp) @@ -317,48 +272,13 @@ func (suite *AuditPublicTestSuite) TestExport() { suite.Empty(resp.Data.Items) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"items":[],"total_items":0}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Audit.Export(suite.ctx) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *AuditPublicTestSuite) TestExportError() { - tests := []struct { - name string - setupServer func() *httptest.Server - validateFunc func(*osapi.Response[osapi.AuditList], error) - }{ { name: "when server returns 401 returns AuthError", - setupServer: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) - }), - ) - }, + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) + }), validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.Error(err) suite.Nil(resp) @@ -369,15 +289,8 @@ func (suite *AuditPublicTestSuite) TestExportError() { }, }, { - name: "when HTTP request fails returns error", - setupServer: func() *httptest.Server { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - return server - }, + name: "when client HTTP request fails returns error", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.Error(err) suite.Nil(resp) @@ -386,14 +299,10 @@ func (suite *AuditPublicTestSuite) TestExportError() { }, { name: "when response body is nil returns UnexpectedStatusError", - setupServer: func() *httptest.Server { - return httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - }), - ) - }, + handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + }), validateFunc: func(resp *osapi.Response[osapi.AuditList], err error) { suite.Error(err) suite.Nil(resp) @@ -408,11 +317,15 @@ func (suite *AuditPublicTestSuite) TestExportError() { for _, tc := range tests { suite.Run(tc.name, func() { - server := tc.setupServer() - defer server.Close() + serverURL := tc.serverURL + if tc.handler != nil { + server := httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) diff --git a/pkg/osapi/errors.go b/pkg/osapi/errors.go index 51854bc..508e742 100644 --- a/pkg/osapi/errors.go +++ b/pkg/osapi/errors.go @@ -77,6 +77,16 @@ func (e *ServerError) Unwrap() error { return &e.APIError } +// ConflictError represents conflict errors (409). +type ConflictError struct { + APIError +} + +// Unwrap returns the underlying APIError. +func (e *ConflictError) Unwrap() error { + return &e.APIError +} + // UnexpectedStatusError represents unexpected HTTP status codes. type UnexpectedStatusError struct { APIError diff --git a/pkg/osapi/errors_public_test.go b/pkg/osapi/errors_public_test.go index c4e1c34..776a69b 100644 --- a/pkg/osapi/errors_public_test.go +++ b/pkg/osapi/errors_public_test.go @@ -113,6 +113,21 @@ func (suite *ErrorsPublicTestSuite) TestErrorFormat() { ) }, }, + { + name: "when ConflictError formats correctly", + err: &osapi.ConflictError{ + APIError: osapi.APIError{ + StatusCode: 409, + Message: "already draining", + }, + }, + validateFunc: func(err error) { + suite.Equal( + "api error (status 409): already draining", + err.Error(), + ) + }, + }, { name: "when UnexpectedStatusError formats correctly", err: &osapi.UnexpectedStatusError{ @@ -203,6 +218,21 @@ func (suite *ErrorsPublicTestSuite) TestErrorsAsUnwrap() { suite.Equal("server failure", target.Message) }, }, + { + name: "when ConflictError is unwrapped via errors.As", + err: fmt.Errorf("wrapped: %w", &osapi.ConflictError{ + APIError: osapi.APIError{ + StatusCode: 409, + Message: "already draining", + }, + }), + validateFunc: func(err error) { + var target *osapi.ConflictError + suite.True(errors.As(err, &target)) + suite.Equal(409, target.StatusCode) + suite.Equal("already draining", target.Message) + }, + }, { name: "when UnexpectedStatusError is unwrapped via errors.As", err: fmt.Errorf("wrapped: %w", &osapi.UnexpectedStatusError{ @@ -293,6 +323,21 @@ func (suite *ErrorsPublicTestSuite) TestErrorsAsAPIError() { suite.Equal("internal error", target.Message) }, }, + { + name: "when ConflictError is matchable as APIError", + err: fmt.Errorf("wrapped: %w", &osapi.ConflictError{ + APIError: osapi.APIError{ + StatusCode: 409, + Message: "conflict", + }, + }), + validateFunc: func(err error) { + var target *osapi.APIError + suite.True(errors.As(err, &target)) + suite.Equal(409, target.StatusCode) + suite.Equal("conflict", target.Message) + }, + }, { name: "when UnexpectedStatusError is matchable as APIError", err: fmt.Errorf("wrapped: %w", &osapi.UnexpectedStatusError{ diff --git a/pkg/osapi/gen/api.yaml b/pkg/osapi/gen/api.yaml index 0dbe61d..104c36d 100644 --- a/pkg/osapi/gen/api.yaml +++ b/pkg/osapi/gen/api.yaml @@ -118,6 +118,116 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' + /agent/{hostname}/drain: + servers: [] + post: + operationId: drainAgent + summary: Drain an agent + description: > + Stop the agent from accepting new jobs. In-flight jobs continue to + completion. + tags: + - Agent_Management_API_agent_operations + security: + - BearerAuth: + - agent:write + parameters: + - name: hostname + in: path + required: true + schema: + type: string + description: The hostname of the agent to drain. + responses: + '200': + description: Agent drain initiated. + content: + application/json: + schema: + type: object + properties: + message: + type: string + required: + - message + '401': + description: Unauthorized - API key required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - Insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Agent not found. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '409': + description: Agent already in requested state. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /agent/{hostname}/undrain: + servers: [] + post: + operationId: undrainAgent + summary: Undrain an agent + description: Resume accepting jobs on a drained agent. + tags: + - Agent_Management_API_agent_operations + security: + - BearerAuth: + - agent:write + parameters: + - name: hostname + in: path + required: true + schema: + type: string + description: The hostname of the agent to undrain. + responses: + '200': + description: Agent undrain initiated. + content: + application/json: + schema: + type: object + properties: + message: + type: string + required: + - message + '401': + description: Unauthorized - API key required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - Insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Agent not found. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '409': + description: Agent not in draining or cordoned state. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' /audit: servers: [] get: @@ -1380,6 +1490,23 @@ components: type: object additionalProperties: true description: Extended facts from additional providers. + state: + type: string + enum: + - Ready + - Draining + - Cordoned + description: Agent scheduling state. + conditions: + type: array + items: + $ref: '#/components/schemas/NodeCondition' + description: Evaluated node conditions. + timeline: + type: array + items: + $ref: '#/components/schemas/TimelineEvent' + description: Agent state transition history. required: - hostname - status @@ -1463,6 +1590,43 @@ components: - dual required: - name + NodeCondition: + type: object + properties: + type: + type: string + enum: + - MemoryPressure + - HighLoad + - DiskPressure + status: + type: boolean + reason: + type: string + last_transition_time: + type: string + format: date-time + required: + - type + - status + - last_transition_time + TimelineEvent: + type: object + properties: + timestamp: + type: string + format: date-time + event: + type: string + hostname: + type: string + message: + type: string + error: + type: string + required: + - timestamp + - event AuditEntry: type: object properties: diff --git a/pkg/osapi/gen/client.gen.go b/pkg/osapi/gen/client.gen.go index 5780c87..72dc1a5 100644 --- a/pkg/osapi/gen/client.gen.go +++ b/pkg/osapi/gen/client.gen.go @@ -22,10 +22,17 @@ const ( BearerAuthScopes = "BearerAuth.Scopes" ) +// Defines values for AgentInfoState. +const ( + AgentInfoStateCordoned AgentInfoState = "Cordoned" + AgentInfoStateDraining AgentInfoState = "Draining" + AgentInfoStateReady AgentInfoState = "Ready" +) + // Defines values for AgentInfoStatus. const ( - NotReady AgentInfoStatus = "NotReady" - Ready AgentInfoStatus = "Ready" + AgentInfoStatusNotReady AgentInfoStatus = "NotReady" + AgentInfoStatusReady AgentInfoStatus = "Ready" ) // Defines values for DNSUpdateResultItemStatus. @@ -41,6 +48,13 @@ const ( Inet6 NetworkInterfaceResponseFamily = "inet6" ) +// Defines values for NodeConditionType. +const ( + DiskPressure NodeConditionType = "DiskPressure" + HighLoad NodeConditionType = "HighLoad" + MemoryPressure NodeConditionType = "MemoryPressure" +) + // Defines values for GetJobParamsStatus. const ( GetJobParamsStatusCompleted GetJobParamsStatus = "completed" @@ -67,6 +81,9 @@ type AgentInfo struct { // Architecture CPU architecture. Architecture *string `json:"architecture,omitempty"` + // Conditions Evaluated node conditions. + Conditions *[]NodeCondition `json:"conditions,omitempty"` + // CpuCount Number of logical CPUs. CpuCount *int `json:"cpu_count,omitempty"` @@ -107,13 +124,22 @@ type AgentInfo struct { // StartedAt When the agent process started. StartedAt *time.Time `json:"started_at,omitempty"` + // State Agent scheduling state. + State *AgentInfoState `json:"state,omitempty"` + // Status The current status of the agent. Status AgentInfoStatus `json:"status"` + // Timeline Agent state transition history. + Timeline *[]TimelineEvent `json:"timeline,omitempty"` + // Uptime The system uptime. Uptime *string `json:"uptime,omitempty"` } +// AgentInfoState Agent scheduling state. +type AgentInfoState string + // AgentInfoStatus The current status of the agent. type AgentInfoStatus string @@ -612,6 +638,17 @@ type NetworkInterfaceResponse struct { // NetworkInterfaceResponseFamily IP address family. type NetworkInterfaceResponseFamily string +// NodeCondition defines model for NodeCondition. +type NodeCondition struct { + LastTransitionTime time.Time `json:"last_transition_time"` + Reason *string `json:"reason,omitempty"` + Status bool `json:"status"` + Type NodeConditionType `json:"type"` +} + +// NodeConditionType defines model for NodeCondition.Type. +type NodeConditionType string + // NodeStatusCollectionResponse defines model for NodeStatusCollectionResponse. type NodeStatusCollectionResponse struct { // JobId The job ID used to process this request. @@ -776,6 +813,15 @@ type StreamInfo struct { Name string `json:"name"` } +// TimelineEvent defines model for TimelineEvent. +type TimelineEvent struct { + Error *string `json:"error,omitempty"` + Event string `json:"event"` + Hostname *string `json:"hostname,omitempty"` + Message *string `json:"message,omitempty"` + Timestamp time.Time `json:"timestamp"` +} + // UptimeCollectionResponse defines model for UptimeCollectionResponse. type UptimeCollectionResponse struct { // JobId The job ID used to process this request. @@ -925,6 +971,12 @@ type ClientInterface interface { // GetAgentDetails request GetAgentDetails(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) + // DrainAgent request + DrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // UndrainAgent request + UndrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetAuditLogs request GetAuditLogs(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1037,6 +1089,30 @@ func (c *Client) GetAgentDetails(ctx context.Context, hostname string, reqEditor return c.Client.Do(req) } +func (c *Client) DrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDrainAgentRequest(c.Server, hostname) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) UndrainAgent(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewUndrainAgentRequest(c.Server, hostname) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) GetAuditLogs(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewGetAuditLogsRequest(c.Server, params) if err != nil { @@ -1470,6 +1546,74 @@ func NewGetAgentDetailsRequest(server string, hostname string) (*http.Request, e return req, nil } +// NewDrainAgentRequest generates requests for DrainAgent +func NewDrainAgentRequest(server string, hostname string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "hostname", runtime.ParamLocationPath, hostname) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/agent/%s/drain", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewUndrainAgentRequest generates requests for UndrainAgent +func NewUndrainAgentRequest(server string, hostname string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "hostname", runtime.ParamLocationPath, hostname) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/agent/%s/undrain", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewGetAuditLogsRequest generates requests for GetAuditLogs func NewGetAuditLogsRequest(server string, params *GetAuditLogsParams) (*http.Request, error) { var err error @@ -2483,6 +2627,12 @@ type ClientWithResponsesInterface interface { // GetAgentDetailsWithResponse request GetAgentDetailsWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*GetAgentDetailsResponse, error) + // DrainAgentWithResponse request + DrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*DrainAgentResponse, error) + + // UndrainAgentWithResponse request + UndrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*UndrainAgentResponse, error) + // GetAuditLogsWithResponse request GetAuditLogsWithResponse(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*GetAuditLogsResponse, error) @@ -2622,6 +2772,62 @@ func (r GetAgentDetailsResponse) StatusCode() int { return 0 } +type DrainAgentResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Message string `json:"message"` + } + JSON401 *ErrorResponse + JSON403 *ErrorResponse + JSON404 *ErrorResponse + JSON409 *ErrorResponse +} + +// Status returns HTTPResponse.Status +func (r DrainAgentResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DrainAgentResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type UndrainAgentResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Message string `json:"message"` + } + JSON401 *ErrorResponse + JSON403 *ErrorResponse + JSON404 *ErrorResponse + JSON409 *ErrorResponse +} + +// Status returns HTTPResponse.Status +func (r UndrainAgentResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r UndrainAgentResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetAuditLogsResponse struct { Body []byte HTTPResponse *http.Response @@ -3278,6 +3484,24 @@ func (c *ClientWithResponses) GetAgentDetailsWithResponse(ctx context.Context, h return ParseGetAgentDetailsResponse(rsp) } +// DrainAgentWithResponse request returning *DrainAgentResponse +func (c *ClientWithResponses) DrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*DrainAgentResponse, error) { + rsp, err := c.DrainAgent(ctx, hostname, reqEditors...) + if err != nil { + return nil, err + } + return ParseDrainAgentResponse(rsp) +} + +// UndrainAgentWithResponse request returning *UndrainAgentResponse +func (c *ClientWithResponses) UndrainAgentWithResponse(ctx context.Context, hostname string, reqEditors ...RequestEditorFn) (*UndrainAgentResponse, error) { + rsp, err := c.UndrainAgent(ctx, hostname, reqEditors...) + if err != nil { + return nil, err + } + return ParseUndrainAgentResponse(rsp) +} + // GetAuditLogsWithResponse request returning *GetAuditLogsResponse func (c *ClientWithResponses) GetAuditLogsWithResponse(ctx context.Context, params *GetAuditLogsParams, reqEditors ...RequestEditorFn) (*GetAuditLogsResponse, error) { rsp, err := c.GetAuditLogs(ctx, params, reqEditors...) @@ -3652,6 +3876,118 @@ func ParseGetAgentDetailsResponse(rsp *http.Response) (*GetAgentDetailsResponse, return response, nil } +// ParseDrainAgentResponse parses an HTTP response from a DrainAgentWithResponse call +func ParseDrainAgentResponse(rsp *http.Response) (*DrainAgentResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DrainAgentResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Message string `json:"message"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + } + + return response, nil +} + +// ParseUndrainAgentResponse parses an HTTP response from a UndrainAgentWithResponse call +func ParseUndrainAgentResponse(rsp *http.Response) (*UndrainAgentResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &UndrainAgentResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Message string `json:"message"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + var dest ErrorResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + } + + return response, nil +} + // ParseGetAuditLogsResponse parses an HTTP response from a GetAuditLogsWithResponse call func ParseGetAuditLogsResponse(rsp *http.Response) (*GetAuditLogsResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/pkg/osapi/health_public_test.go b/pkg/osapi/health_public_test.go index aa784d7..6a7e54c 100644 --- a/pkg/osapi/health_public_test.go +++ b/pkg/osapi/health_public_test.go @@ -43,6 +43,19 @@ func (suite *HealthPublicTestSuite) SetupTest() { suite.ctx = context.Background() } +func (suite *HealthPublicTestSuite) runner( + handler http.HandlerFunc, + serverURL string, +) string { + if handler != nil { + server := httptest.NewServer(handler) + suite.T().Cleanup(server.Close) + return server.URL + } + + return serverURL +} + func (suite *HealthPublicTestSuite) TestLiveness() { tests := []struct { name string @@ -92,15 +105,8 @@ func (suite *HealthPublicTestSuite) TestLiveness() { for _, tc := range tests { suite.Run(tc.name, func() { - serverURL := tc.serverURL - if tc.handler != nil { - server := httptest.NewServer(tc.handler) - defer server.Close() - serverURL = server.URL - } - sut := osapi.New( - serverURL, + suite.runner(tc.handler, tc.serverURL), "test-token", osapi.WithLogger(slog.Default()), ) @@ -173,35 +179,6 @@ func (suite *HealthPublicTestSuite) TestReady() { suite.Contains(target.Message, "unexpected status") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - serverURL := tc.serverURL - if tc.handler != nil { - server := httptest.NewServer(tc.handler) - defer server.Close() - serverURL = server.URL - } - - sut := osapi.New( - serverURL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Health.Ready(suite.ctx) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *HealthPublicTestSuite) TestReady503() { - tests := []struct { - name string - handler http.HandlerFunc - validateFunc func(*osapi.Response[osapi.ReadyStatus], error) - }{ { name: "when server returns 503 returns ready status with ServiceUnavailable", handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { @@ -237,11 +214,8 @@ func (suite *HealthPublicTestSuite) TestReady503() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer(tc.handler) - defer server.Close() - sut := osapi.New( - server.URL, + suite.runner(tc.handler, tc.serverURL), "test-token", osapi.WithLogger(slog.Default()), ) @@ -316,35 +290,6 @@ func (suite *HealthPublicTestSuite) TestStatus() { suite.Contains(target.Message, "unexpected status") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - serverURL := tc.serverURL - if tc.handler != nil { - server := httptest.NewServer(tc.handler) - defer server.Close() - serverURL = server.URL - } - - sut := osapi.New( - serverURL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Health.Status(suite.ctx) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *HealthPublicTestSuite) TestStatus503() { - tests := []struct { - name string - handler http.HandlerFunc - validateFunc func(*osapi.Response[osapi.SystemStatus], error) - }{ { name: "when server returns 503 returns status with ServiceUnavailable", handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { @@ -375,31 +320,6 @@ func (suite *HealthPublicTestSuite) TestStatus503() { suite.Contains(target.Message, "nil response body") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer(tc.handler) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Health.Status(suite.ctx) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *HealthPublicTestSuite) TestStatusAuthError() { - tests := []struct { - name string - handler http.HandlerFunc - validateFunc func(*osapi.Response[osapi.SystemStatus], error) - }{ { name: "when server returns 401 returns AuthError", handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { @@ -436,11 +356,8 @@ func (suite *HealthPublicTestSuite) TestStatusAuthError() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer(tc.handler) - defer server.Close() - sut := osapi.New( - server.URL, + suite.runner(tc.handler, tc.serverURL), "test-token", osapi.WithLogger(slog.Default()), ) diff --git a/pkg/osapi/job_public_test.go b/pkg/osapi/job_public_test.go index 0722079..8fb7cea 100644 --- a/pkg/osapi/job_public_test.go +++ b/pkg/osapi/job_public_test.go @@ -46,12 +46,23 @@ func (suite *JobPublicTestSuite) SetupTest() { func (suite *JobPublicTestSuite) TestCreate() { tests := []struct { name string + handler http.HandlerFunc + serverURL string operation map[string]interface{} target string validateFunc func(*osapi.Response[osapi.JobCreated], error) }{ { - name: "when creating job returns response", + name: "when creating job returns response", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _, _ = w.Write( + []byte( + `{"job_id":"550e8400-e29b-41d4-a716-446655440000","status":"pending"}`, + ), + ) + }, operation: map[string]interface{}{"type": "system.hostname.get"}, target: "_any", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { @@ -61,42 +72,15 @@ func (suite *JobPublicTestSuite) TestCreate() { suite.Equal("pending", resp.Data.Status) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - _, _ = w.Write( - []byte( - `{"job_id":"550e8400-e29b-41d4-a716-446655440000","status":"pending"}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Create(suite.ctx, tc.operation, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestCreateError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobCreated], error) - }{ { name: "when server returns 400 returns ValidationError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(`{"error":"validation failed"}`)) + }, + operation: map[string]interface{}{}, + target: "_any", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { suite.Error(err) suite.Nil(resp) @@ -106,72 +90,24 @@ func (suite *JobPublicTestSuite) TestCreateError() { suite.Equal(http.StatusBadRequest, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(`{"error":"validation failed"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Create(suite.ctx, map[string]interface{}{}, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestCreateHTTPError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobCreated], error) - }{ { - name: "when HTTP request fails returns error", + name: "when HTTP request fails returns error", + serverURL: "http://127.0.0.1:0", + operation: map[string]interface{}{}, + target: "_any", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "create job") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Create(suite.ctx, map[string]interface{}{}, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestCreateNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobCreated], error) - }{ { name: "when server returns 201 with empty body returns UnexpectedStatusError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusCreated) + }, + operation: map[string]interface{}{}, + target: "_any", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { suite.Error(err) suite.Nil(resp) @@ -185,20 +121,26 @@ func (suite *JobPublicTestSuite) TestCreateNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusCreated) - }), + var ( + serverURL string + server *httptest.Server ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + } else { + server = httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Job.Create(suite.ctx, map[string]interface{}{}, "_any") + resp, err := sut.Job.Create(suite.ctx, tc.operation, tc.target) tc.validateFunc(resp, err) }) } @@ -207,12 +149,23 @@ func (suite *JobPublicTestSuite) TestCreateNilResponse() { func (suite *JobPublicTestSuite) TestGet() { tests := []struct { name string + handler http.HandlerFunc + serverURL string id string validateFunc func(*osapi.Response[osapi.JobDetail], error) }{ { name: "when valid UUID returns response", - id: "550e8400-e29b-41d4-a716-446655440000", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte( + `{"id":"550e8400-e29b-41d4-a716-446655440000","status":"completed"}`, + ), + ) + }, + id: "550e8400-e29b-41d4-a716-446655440000", validateFunc: func(resp *osapi.Response[osapi.JobDetail], err error) { suite.NoError(err) suite.NotNil(resp) @@ -222,83 +175,38 @@ func (suite *JobPublicTestSuite) TestGet() { }, { name: "when invalid UUID returns error", - id: "not-a-uuid", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte( + `{"id":"550e8400-e29b-41d4-a716-446655440000","status":"completed"}`, + ), + ) + }, + id: "not-a-uuid", validateFunc: func(resp *osapi.Response[osapi.JobDetail], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "invalid job ID") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write( - []byte( - `{"id":"550e8400-e29b-41d4-a716-446655440000","status":"completed"}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Get(suite.ctx, tc.id) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestGetHTTPError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobDetail], error) - }{ { - name: "when HTTP request fails returns error", + name: "when HTTP request fails returns error", + serverURL: "http://127.0.0.1:0", + id: "00000000-0000-0000-0000-000000000000", validateFunc: func(resp *osapi.Response[osapi.JobDetail], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "get job") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Get(suite.ctx, "00000000-0000-0000-0000-000000000000") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestGetNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobDetail], error) - }{ { name: "when server returns 200 with empty body returns UnexpectedStatusError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, + id: "00000000-0000-0000-0000-000000000000", validateFunc: func(resp *osapi.Response[osapi.JobDetail], err error) { suite.Error(err) suite.Nil(resp) @@ -308,36 +216,14 @@ func (suite *JobPublicTestSuite) TestGetNilResponse() { suite.Contains(target.Message, "nil response body") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Get(suite.ctx, "00000000-0000-0000-0000-000000000000") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestGetNotFound() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobDetail], error) - }{ { name: "when server returns 404 returns NotFoundError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"error":"job not found"}`)) + }, + id: "550e8400-e29b-41d4-a716-446655440000", validateFunc: func(resp *osapi.Response[osapi.JobDetail], err error) { suite.Error(err) suite.Nil(resp) @@ -352,22 +238,26 @@ func (suite *JobPublicTestSuite) TestGetNotFound() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"error":"job not found"}`)) - }), + var ( + serverURL string + server *httptest.Server ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + } else { + server = httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Job.Get(suite.ctx, "550e8400-e29b-41d4-a716-446655440000") + resp, err := sut.Job.Get(suite.ctx, tc.id) tc.validateFunc(resp, err) }) } @@ -376,87 +266,49 @@ func (suite *JobPublicTestSuite) TestGetNotFound() { func (suite *JobPublicTestSuite) TestDelete() { tests := []struct { name string + handler http.HandlerFunc + serverURL string id string validateFunc func(error) }{ { name: "when valid UUID returns no error", - id: "550e8400-e29b-41d4-a716-446655440000", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }, + id: "550e8400-e29b-41d4-a716-446655440000", validateFunc: func(err error) { suite.NoError(err) }, }, { name: "when invalid UUID returns error", - id: "not-a-uuid", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }, + id: "not-a-uuid", validateFunc: func(err error) { suite.Error(err) suite.Contains(err.Error(), "invalid job ID") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNoContent) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - err := sut.Job.Delete(suite.ctx, tc.id) - tc.validateFunc(err) - }) - } -} - -func (suite *JobPublicTestSuite) TestDeleteHTTPError() { - tests := []struct { - name string - validateFunc func(error) - }{ { - name: "when HTTP request fails returns error", + name: "when HTTP request fails returns error", + serverURL: "http://127.0.0.1:0", + id: "00000000-0000-0000-0000-000000000000", validateFunc: func(err error) { suite.Error(err) suite.Contains(err.Error(), "delete job") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - err := sut.Job.Delete(suite.ctx, "00000000-0000-0000-0000-000000000000") - tc.validateFunc(err) - }) - } -} - -func (suite *JobPublicTestSuite) TestDeleteNotFound() { - tests := []struct { - name string - validateFunc func(error) - }{ { name: "when server returns 404 returns NotFoundError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"error":"job not found"}`)) + }, + id: "550e8400-e29b-41d4-a716-446655440000", validateFunc: func(err error) { suite.Error(err) @@ -470,22 +322,26 @@ func (suite *JobPublicTestSuite) TestDeleteNotFound() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"error":"job not found"}`)) - }), + var ( + serverURL string + server *httptest.Server ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + } else { + server = httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - err := sut.Job.Delete(suite.ctx, "550e8400-e29b-41d4-a716-446655440000") + err := sut.Job.Delete(suite.ctx, tc.id) tc.validateFunc(err) }) } @@ -494,11 +350,18 @@ func (suite *JobPublicTestSuite) TestDeleteNotFound() { func (suite *JobPublicTestSuite) TestList() { tests := []struct { name string + handler http.HandlerFunc + serverURL string params osapi.ListParams validateFunc func(*osapi.Response[osapi.JobList], error) }{ { - name: "when no filters returns response", + name: "when no filters returns response", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"items":[],"total_items":0}`)) + }, params: osapi.ListParams{}, validateFunc: func(resp *osapi.Response[osapi.JobList], err error) { suite.NoError(err) @@ -509,6 +372,11 @@ func (suite *JobPublicTestSuite) TestList() { }, { name: "when all filters provided returns response", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"items":[],"total_items":0}`)) + }, params: osapi.ListParams{ Status: "completed", Limit: 10, @@ -519,72 +387,24 @@ func (suite *JobPublicTestSuite) TestList() { suite.NotNil(resp) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"items":[],"total_items":0}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.List(suite.ctx, tc.params) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestListHTTPError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobList], error) - }{ { - name: "when HTTP request fails returns error", + name: "when HTTP request fails returns error", + serverURL: "http://127.0.0.1:0", + params: osapi.ListParams{}, validateFunc: func(resp *osapi.Response[osapi.JobList], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "list jobs") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.List(suite.ctx, osapi.ListParams{}) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestListError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobList], error) - }{ { name: "when server returns 401 returns AuthError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) + }, + params: osapi.ListParams{}, validateFunc: func(resp *osapi.Response[osapi.JobList], err error) { suite.Error(err) suite.Nil(resp) @@ -594,38 +414,12 @@ func (suite *JobPublicTestSuite) TestListError() { suite.Equal(http.StatusUnauthorized, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.List(suite.ctx, osapi.ListParams{}) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestListNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobList], error) - }{ { name: "when server returns 200 with empty body returns UnexpectedStatusError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, + params: osapi.ListParams{}, validateFunc: func(resp *osapi.Response[osapi.JobList], err error) { suite.Error(err) suite.Nil(resp) @@ -639,20 +433,26 @@ func (suite *JobPublicTestSuite) TestListNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + server *httptest.Server ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + } else { + server = httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Job.List(suite.ctx, osapi.ListParams{}) + resp, err := sut.Job.List(suite.ctx, tc.params) tc.validateFunc(resp, err) }) } @@ -661,82 +461,39 @@ func (suite *JobPublicTestSuite) TestListNilResponse() { func (suite *JobPublicTestSuite) TestQueueStats() { tests := []struct { name string + handler http.HandlerFunc + serverURL string validateFunc func(*osapi.Response[osapi.QueueStats], error) }{ { name: "when requesting queue stats returns response", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"total_jobs":5}`)) + }, validateFunc: func(resp *osapi.Response[osapi.QueueStats], err error) { suite.NoError(err) suite.NotNil(resp) suite.Equal(5, resp.Data.TotalJobs) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"total_jobs":5}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.QueueStats(suite.ctx) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestQueueStatsHTTPError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.QueueStats], error) - }{ { - name: "when HTTP request fails returns error", + name: "when HTTP request fails returns error", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.QueueStats], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "queue stats") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.QueueStats(suite.ctx) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestQueueStatsError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.QueueStats], error) - }{ { name: "when server returns 401 returns AuthError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.QueueStats], err error) { suite.Error(err) suite.Nil(resp) @@ -746,38 +503,11 @@ func (suite *JobPublicTestSuite) TestQueueStatsError() { suite.Equal(http.StatusUnauthorized, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"error":"unauthorized"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.QueueStats(suite.ctx) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestQueueStatsNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.QueueStats], error) - }{ { name: "when server returns 200 with empty body returns UnexpectedStatusError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.QueueStats], err error) { suite.Error(err) suite.Nil(resp) @@ -791,15 +521,21 @@ func (suite *JobPublicTestSuite) TestQueueStatsNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + server *httptest.Server ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + } else { + server = httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) @@ -813,12 +549,23 @@ func (suite *JobPublicTestSuite) TestQueueStatsNilResponse() { func (suite *JobPublicTestSuite) TestRetry() { tests := []struct { name string + handler http.HandlerFunc + serverURL string id string target string validateFunc func(*osapi.Response[osapi.JobCreated], error) }{ { - name: "when valid UUID with empty target returns response", + name: "when valid UUID with empty target returns response", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _, _ = w.Write( + []byte( + `{"job_id":"550e8400-e29b-41d4-a716-446655440000","status":"pending"}`, + ), + ) + }, id: "550e8400-e29b-41d4-a716-446655440000", target: "", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { @@ -829,7 +576,16 @@ func (suite *JobPublicTestSuite) TestRetry() { }, }, { - name: "when valid UUID with target returns response", + name: "when valid UUID with target returns response", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _, _ = w.Write( + []byte( + `{"job_id":"550e8400-e29b-41d4-a716-446655440000","status":"pending"}`, + ), + ) + }, id: "550e8400-e29b-41d4-a716-446655440000", target: "web-01", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { @@ -838,7 +594,16 @@ func (suite *JobPublicTestSuite) TestRetry() { }, }, { - name: "when invalid UUID returns error", + name: "when invalid UUID returns error", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + _, _ = w.Write( + []byte( + `{"job_id":"550e8400-e29b-41d4-a716-446655440000","status":"pending"}`, + ), + ) + }, id: "not-a-uuid", target: "", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { @@ -847,80 +612,26 @@ func (suite *JobPublicTestSuite) TestRetry() { suite.Contains(err.Error(), "invalid job ID") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - _, _ = w.Write( - []byte( - `{"job_id":"550e8400-e29b-41d4-a716-446655440000","status":"pending"}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Retry(suite.ctx, tc.id, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestRetryHTTPError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobCreated], error) - }{ { - name: "when HTTP request fails returns error", + name: "when HTTP request fails returns error", + serverURL: "http://127.0.0.1:0", + id: "00000000-0000-0000-0000-000000000000", + target: "", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "retry job") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Retry( - suite.ctx, - "00000000-0000-0000-0000-000000000000", - "", - ) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestRetryError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobCreated], error) - }{ { name: "when server returns 404 returns NotFoundError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"error":"job not found"}`)) + }, + id: "00000000-0000-0000-0000-000000000000", + target: "", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { suite.Error(err) suite.Nil(resp) @@ -930,42 +641,13 @@ func (suite *JobPublicTestSuite) TestRetryError() { suite.Equal(http.StatusNotFound, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"error":"job not found"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Job.Retry( - suite.ctx, - "00000000-0000-0000-0000-000000000000", - "", - ) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *JobPublicTestSuite) TestRetryNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.JobCreated], error) - }{ { name: "when server returns 201 with empty body returns UnexpectedStatusError", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusCreated) + }, + id: "00000000-0000-0000-0000-000000000000", + target: "", validateFunc: func(resp *osapi.Response[osapi.JobCreated], err error) { suite.Error(err) suite.Nil(resp) @@ -979,24 +661,26 @@ func (suite *JobPublicTestSuite) TestRetryNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusCreated) - }), + var ( + serverURL string + server *httptest.Server ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + } else { + server = httptest.NewServer(tc.handler) + defer server.Close() + serverURL = server.URL + } sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Job.Retry( - suite.ctx, - "00000000-0000-0000-0000-000000000000", - "", - ) + resp, err := sut.Job.Retry(suite.ctx, tc.id, tc.target) tc.validateFunc(resp, err) }) } diff --git a/pkg/osapi/job_types.go b/pkg/osapi/job_types.go index ccd30fc..e37e494 100644 --- a/pkg/osapi/job_types.go +++ b/pkg/osapi/job_types.go @@ -62,15 +62,6 @@ type AgentJobResponse struct { Data any } -// TimelineEvent represents a job lifecycle event. -type TimelineEvent struct { - Timestamp string - Event string - Hostname string - Message string - Error string -} - // JobList is a paginated list of jobs. type JobList struct { Items []JobDetail diff --git a/pkg/osapi/metrics_public_test.go b/pkg/osapi/metrics_public_test.go index ce9ce62..d5df1cb 100644 --- a/pkg/osapi/metrics_public_test.go +++ b/pkg/osapi/metrics_public_test.go @@ -43,122 +43,62 @@ func (suite *MetricsPublicTestSuite) SetupTest() { } func (suite *MetricsPublicTestSuite) TestGet() { + closedServer := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }), + ) + closedServerURL := closedServer.URL + closedServer.Close() + tests := []struct { name string + handler http.HandlerFunc + serverURL string + ctx context.Context validateFunc func(string, error) }{ { name: "when server returns metrics returns text body", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("# HELP go_goroutines\n")) + }, + ctx: suite.ctx, validateFunc: func(body string, err error) { suite.NoError(err) suite.Equal("# HELP go_goroutines\n", body) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("# HELP go_goroutines\n")) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - body, err := sut.Metrics.Get(suite.ctx) - tc.validateFunc(body, err) - }) - } -} - -func (suite *MetricsPublicTestSuite) TestGetErrorStatus() { - tests := []struct { - name string - validateFunc func(string, error) - }{ { name: "when server returns non-200 returns error", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + }, + ctx: suite.ctx, validateFunc: func(body string, err error) { suite.Error(err) suite.Contains(err.Error(), "metrics endpoint returned status") suite.Empty(body) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - body, err := sut.Metrics.Get(suite.ctx) - tc.validateFunc(body, err) - }) - } -} - -func (suite *MetricsPublicTestSuite) TestGetRequestError() { - tests := []struct { - name string - validateFunc func(string, error) - }{ { - name: "when server is unreachable returns error", + name: "when server is unreachable returns error", + serverURL: closedServerURL, + ctx: suite.ctx, validateFunc: func(body string, err error) { suite.Error(err) suite.Contains(err.Error(), "fetching metrics") suite.Empty(body) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), - ) - closedURL := server.URL - server.Close() - - sut := osapi.New( - closedURL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - body, err := sut.Metrics.Get(suite.ctx) - tc.validateFunc(body, err) - }) - } -} - -func (suite *MetricsPublicTestSuite) TestGetCreateRequestError() { - tests := []struct { - name string - validateFunc func(string, error) - }{ { name: "when request creation fails returns error", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, + ctx: nil, validateFunc: func(body string, err error) { suite.Error(err) suite.Contains(err.Error(), "creating metrics request") @@ -169,21 +109,24 @@ func (suite *MetricsPublicTestSuite) TestGetCreateRequestError() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), - ) - defer server.Close() + var targetURL string + + if tc.serverURL != "" { + targetURL = tc.serverURL + } else { + server := httptest.NewServer(tc.handler) + defer server.Close() + targetURL = server.URL + } sut := osapi.New( - server.URL, + targetURL, "test-token", osapi.WithLogger(slog.Default()), ) //nolint:staticcheck // nil context intentionally triggers NewRequestWithContext error - body, err := sut.Metrics.Get(nil) + body, err := sut.Metrics.Get(tc.ctx) tc.validateFunc(body, err) }) } diff --git a/pkg/osapi/node_public_test.go b/pkg/osapi/node_public_test.go index e4752d9..63e3a30 100644 --- a/pkg/osapi/node_public_test.go +++ b/pkg/osapi/node_public_test.go @@ -46,12 +46,23 @@ func (suite *NodePublicTestSuite) SetupTest() { func (suite *NodePublicTestSuite) TestHostname() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string validateFunc func(*osapi.Response[osapi.Collection[osapi.HostnameResult]], error) }{ { name: "when requesting hostname returns results", target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte( + `{"job_id":"00000000-0000-0000-0000-000000000001","results":[{"hostname":"test-host"}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.HostnameResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -60,145 +71,75 @@ func (suite *NodePublicTestSuite) TestHostname() { suite.Equal("test-host", resp.Data.Results[0].Hostname) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write( - []byte( - `{"job_id":"00000000-0000-0000-0000-000000000001","results":[{"hostname":"test-host"}]}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Hostname(suite.ctx, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestHostnameClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.HostnameResult]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when server returns 403 returns AuthError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.HostnameResult]], err error) { suite.Error(err) suite.Nil(resp) - suite.Contains(err.Error(), "get hostname") + + var target *osapi.AuthError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusForbidden, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Hostname(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestHostnameNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.HostnameResult]], error) - }{ { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when client HTTP call fails returns error", + target: "_any", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.HostnameResult]], err error) { suite.Error(err) suite.Nil(resp) - - var target *osapi.UnexpectedStatusError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusOK, target.StatusCode) - suite.Equal("nil response body", target.Message) + suite.Contains(err.Error(), "get hostname") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Hostname(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestHostnameError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.HostnameResult]], error) - }{ { - name: "when server returns 403 returns AuthError", + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.HostnameResult]], err error) { suite.Error(err) suite.Nil(resp) - var target *osapi.AuthError + var target *osapi.UnexpectedStatusError suite.True(errors.As(err, &target)) - suite.Equal(http.StatusForbidden, target.StatusCode) + suite.Equal(http.StatusOK, target.StatusCode) + suite.Equal("nil response body", target.Message) }, }, } for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Hostname(suite.ctx, "_any") + resp, err := sut.Node.Hostname(suite.ctx, tc.target) tc.validateFunc(resp, err) }) } @@ -207,12 +148,19 @@ func (suite *NodePublicTestSuite) TestHostnameError() { func (suite *NodePublicTestSuite) TestStatus() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string validateFunc func(*osapi.Response[osapi.Collection[osapi.NodeStatus]], error) }{ { name: "when requesting status returns results", target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"results":[{"hostname":"web-01"}]}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.NodeStatus]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -220,38 +168,14 @@ func (suite *NodePublicTestSuite) TestStatus() { suite.Equal("web-01", resp.Data.Results[0].Hostname) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"results":[{"hostname":"web-01"}]}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Status(suite.ctx, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestStatusError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.NodeStatus]], error) - }{ { - name: "when server returns 403 returns AuthError", + name: "when server returns 403 returns AuthError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.NodeStatus]], err error) { suite.Error(err) suite.Nil(resp) @@ -261,72 +185,22 @@ func (suite *NodePublicTestSuite) TestStatusError() { suite.Equal(http.StatusForbidden, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Status(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestStatusClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.NodeStatus]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when client HTTP call fails returns error", + target: "_any", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.NodeStatus]], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "get status") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Status(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestStatusNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.NodeStatus]], error) - }{ { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.NodeStatus]], err error) { suite.Error(err) suite.Nil(resp) @@ -341,20 +215,28 @@ func (suite *NodePublicTestSuite) TestStatusNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Status(suite.ctx, "_any") + resp, err := sut.Node.Status(suite.ctx, tc.target) tc.validateFunc(resp, err) }) } @@ -363,12 +245,19 @@ func (suite *NodePublicTestSuite) TestStatusNilResponse() { func (suite *NodePublicTestSuite) TestDisk() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string validateFunc func(*osapi.Response[osapi.Collection[osapi.DiskResult]], error) }{ { name: "when requesting disk returns results", target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"results":[{"hostname":"disk-host"}]}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DiskResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -376,38 +265,14 @@ func (suite *NodePublicTestSuite) TestDisk() { suite.Equal("disk-host", resp.Data.Results[0].Hostname) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"results":[{"hostname":"disk-host"}]}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Disk(suite.ctx, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestDiskError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DiskResult]], error) - }{ { - name: "when server returns 403 returns AuthError", + name: "when server returns 403 returns AuthError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DiskResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -417,72 +282,22 @@ func (suite *NodePublicTestSuite) TestDiskError() { suite.Equal(http.StatusForbidden, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Disk(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestDiskClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DiskResult]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when client HTTP call fails returns error", + target: "_any", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DiskResult]], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "get disk") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Disk(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestDiskNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DiskResult]], error) - }{ { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DiskResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -497,20 +312,28 @@ func (suite *NodePublicTestSuite) TestDiskNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Disk(suite.ctx, "_any") + resp, err := sut.Node.Disk(suite.ctx, tc.target) tc.validateFunc(resp, err) }) } @@ -519,12 +342,19 @@ func (suite *NodePublicTestSuite) TestDiskNilResponse() { func (suite *NodePublicTestSuite) TestMemory() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string validateFunc func(*osapi.Response[osapi.Collection[osapi.MemoryResult]], error) }{ { name: "when requesting memory returns results", target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"results":[{"hostname":"mem-host"}]}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.MemoryResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -532,21 +362,70 @@ func (suite *NodePublicTestSuite) TestMemory() { suite.Equal("mem-host", resp.Data.Results[0].Hostname) }, }, + { + name: "when server returns 403 returns AuthError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.MemoryResult]], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.AuthError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusForbidden, target.StatusCode) + }, + }, + { + name: "when client HTTP call fails returns error", + target: "_any", + serverURL: "http://127.0.0.1:0", + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.MemoryResult]], err error) { + suite.Error(err) + suite.Nil(resp) + suite.Contains(err.Error(), "get memory") + }, + }, + { + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.MemoryResult]], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.UnexpectedStatusError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusOK, target.StatusCode) + suite.Equal("nil response body", target.Message) + }, + }, } for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"results":[{"hostname":"mem-host"}]}`)) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) @@ -557,130 +436,22 @@ func (suite *NodePublicTestSuite) TestMemory() { } } -func (suite *NodePublicTestSuite) TestMemoryError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.MemoryResult]], error) - }{ - { - name: "when server returns 403 returns AuthError", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.MemoryResult]], err error) { - suite.Error(err) - suite.Nil(resp) - - var target *osapi.AuthError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusForbidden, target.StatusCode) - }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Memory(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestMemoryClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.MemoryResult]], error) - }{ - { - name: "when client HTTP call fails returns error", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.MemoryResult]], err error) { - suite.Error(err) - suite.Nil(resp) - suite.Contains(err.Error(), "get memory") - }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Memory(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestMemoryNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.MemoryResult]], error) - }{ - { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.MemoryResult]], err error) { - suite.Error(err) - suite.Nil(resp) - - var target *osapi.UnexpectedStatusError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusOK, target.StatusCode) - suite.Equal("nil response body", target.Message) - }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Memory(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestLoad() { +func (suite *NodePublicTestSuite) TestLoad() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string validateFunc func(*osapi.Response[osapi.Collection[osapi.LoadResult]], error) }{ { name: "when requesting load returns results", target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"results":[{"hostname":"load-host"}]}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.LoadResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -688,38 +459,14 @@ func (suite *NodePublicTestSuite) TestLoad() { suite.Equal("load-host", resp.Data.Results[0].Hostname) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"results":[{"hostname":"load-host"}]}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Load(suite.ctx, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestLoadError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.LoadResult]], error) - }{ { - name: "when server returns 403 returns AuthError", + name: "when server returns 403 returns AuthError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.LoadResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -729,72 +476,22 @@ func (suite *NodePublicTestSuite) TestLoadError() { suite.Equal(http.StatusForbidden, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Load(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestLoadClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.LoadResult]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when client HTTP call fails returns error", + target: "_any", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.LoadResult]], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "get load") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Load(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestLoadNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.LoadResult]], error) - }{ { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.LoadResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -809,20 +506,28 @@ func (suite *NodePublicTestSuite) TestLoadNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Load(suite.ctx, "_any") + resp, err := sut.Node.Load(suite.ctx, tc.target) tc.validateFunc(resp, err) }) } @@ -831,12 +536,19 @@ func (suite *NodePublicTestSuite) TestLoadNilResponse() { func (suite *NodePublicTestSuite) TestOS() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string validateFunc func(*osapi.Response[osapi.Collection[osapi.OSInfoResult]], error) }{ { name: "when requesting OS info returns results", target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{"results":[{"hostname":"os-host"}]}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.OSInfoResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -844,38 +556,14 @@ func (suite *NodePublicTestSuite) TestOS() { suite.Equal("os-host", resp.Data.Results[0].Hostname) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"results":[{"hostname":"os-host"}]}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.OS(suite.ctx, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestOSError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.OSInfoResult]], error) - }{ { - name: "when server returns 403 returns AuthError", + name: "when server returns 403 returns AuthError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.OSInfoResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -885,72 +573,22 @@ func (suite *NodePublicTestSuite) TestOSError() { suite.Equal(http.StatusForbidden, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.OS(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestOSClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.OSInfoResult]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when client HTTP call fails returns error", + target: "_any", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.OSInfoResult]], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "get os") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.OS(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestOSNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.OSInfoResult]], error) - }{ { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.OSInfoResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -965,20 +603,28 @@ func (suite *NodePublicTestSuite) TestOSNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.OS(suite.ctx, "_any") + resp, err := sut.Node.OS(suite.ctx, tc.target) tc.validateFunc(resp, err) }) } @@ -987,12 +633,21 @@ func (suite *NodePublicTestSuite) TestOSNilResponse() { func (suite *NodePublicTestSuite) TestUptime() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string validateFunc func(*osapi.Response[osapi.Collection[osapi.UptimeResult]], error) }{ { name: "when requesting uptime returns results", target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte(`{"results":[{"hostname":"uptime-host","uptime":"2d3h"}]}`), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.UptimeResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -1001,115 +656,39 @@ func (suite *NodePublicTestSuite) TestUptime() { suite.Equal("2d3h", resp.Data.Results[0].Uptime) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write( - []byte(`{"results":[{"hostname":"uptime-host","uptime":"2d3h"}]}`), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Uptime(suite.ctx, tc.target) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestUptimeError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.UptimeResult]], error) - }{ { - name: "when server returns 403 returns AuthError", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.UptimeResult]], err error) { - suite.Error(err) - suite.Nil(resp) - - var target *osapi.AuthError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusForbidden, target.StatusCode) + name: "when server returns 403 returns AuthError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Uptime(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestUptimeClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.UptimeResult]], error) - }{ - { - name: "when client HTTP call fails returns error", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.UptimeResult]], err error) { suite.Error(err) suite.Nil(resp) - suite.Contains(err.Error(), "get uptime") - }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Uptime(suite.ctx, "_any") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestUptimeNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.UptimeResult]], error) - }{ + + var target *osapi.AuthError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusForbidden, target.StatusCode) + }, + }, + { + name: "when client HTTP call fails returns error", + target: "_any", + serverURL: "http://127.0.0.1:0", + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.UptimeResult]], err error) { + suite.Error(err) + suite.Nil(resp) + suite.Contains(err.Error(), "get uptime") + }, + }, { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.UptimeResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -1124,20 +703,28 @@ func (suite *NodePublicTestSuite) TestUptimeNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Uptime(suite.ctx, "_any") + resp, err := sut.Node.Uptime(suite.ctx, tc.target) tc.validateFunc(resp, err) }) } @@ -1145,15 +732,24 @@ func (suite *NodePublicTestSuite) TestUptimeNilResponse() { func (suite *NodePublicTestSuite) TestGetDNS() { tests := []struct { - name string - target string - iface string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSConfig]], error) + name string + handler http.HandlerFunc + serverURL string + target string + interfaceName string + validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSConfig]], error) }{ { - name: "when requesting DNS returns results", - target: "_any", - iface: "eth0", + name: "when requesting DNS returns results", + target: "_any", + interfaceName: "eth0", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte(`{"results":[{"hostname":"dns-host","servers":["8.8.8.8"]}]}`), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSConfig]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -1162,40 +758,15 @@ func (suite *NodePublicTestSuite) TestGetDNS() { suite.Equal([]string{"8.8.8.8"}, resp.Data.Results[0].Servers) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write( - []byte(`{"results":[{"hostname":"dns-host","servers":["8.8.8.8"]}]}`), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.GetDNS(suite.ctx, tc.target, tc.iface) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestGetDNSError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSConfig]], error) - }{ { - name: "when server returns 403 returns AuthError", + name: "when server returns 403 returns AuthError", + target: "_any", + interfaceName: "eth0", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSConfig]], err error) { suite.Error(err) suite.Nil(resp) @@ -1205,72 +776,24 @@ func (suite *NodePublicTestSuite) TestGetDNSError() { suite.Equal(http.StatusForbidden, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.GetDNS(suite.ctx, "_any", "eth0") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestGetDNSClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSConfig]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when client HTTP call fails returns error", + target: "_any", + interfaceName: "eth0", + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSConfig]], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "get dns") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.GetDNS(suite.ctx, "_any", "eth0") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestGetDNSNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSConfig]], error) - }{ { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + interfaceName: "eth0", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSConfig]], err error) { suite.Error(err) suite.Nil(resp) @@ -1285,20 +808,28 @@ func (suite *NodePublicTestSuite) TestGetDNSNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.GetDNS(suite.ctx, "_any", "eth0") + resp, err := sut.Node.GetDNS(suite.ctx, tc.target, tc.interfaceName) tc.validateFunc(resp, err) }) } @@ -1307,6 +838,8 @@ func (suite *NodePublicTestSuite) TestGetDNSNilResponse() { func (suite *NodePublicTestSuite) TestUpdateDNS() { tests := []struct { name string + handler http.HandlerFunc + serverURL string target string iface string servers []string @@ -1319,6 +852,15 @@ func (suite *NodePublicTestSuite) TestUpdateDNS() { iface: "eth0", servers: []string{"8.8.8.8", "8.8.4.4"}, searchDomains: nil, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"dns-host","status":"completed","changed":true}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -1334,6 +876,15 @@ func (suite *NodePublicTestSuite) TestUpdateDNS() { iface: "eth0", servers: nil, searchDomains: []string{"example.com"}, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"dns-host","status":"completed","changed":true}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -1345,6 +896,15 @@ func (suite *NodePublicTestSuite) TestUpdateDNS() { iface: "eth0", servers: []string{"8.8.8.8"}, searchDomains: []string{"example.com"}, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"dns-host","status":"completed","changed":true}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -1356,53 +916,30 @@ func (suite *NodePublicTestSuite) TestUpdateDNS() { iface: "eth0", servers: nil, searchDomains: nil, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"dns-host","status":"completed","changed":true}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { suite.NoError(err) suite.NotNil(resp) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusAccepted) - _, _ = w.Write( - []byte( - `{"results":[{"hostname":"dns-host","status":"completed","changed":true}]}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.UpdateDNS( - suite.ctx, - tc.target, - tc.iface, - tc.servers, - tc.searchDomains, - ) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestUpdateDNSError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], error) - }{ { - name: "when server returns 403 returns AuthError", + name: "when server returns 403 returns AuthError", + target: "_any", + iface: "eth0", + servers: []string{"8.8.8.8"}, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -1412,235 +949,139 @@ func (suite *NodePublicTestSuite) TestUpdateDNSError() { suite.Equal(http.StatusForbidden, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.UpdateDNS(suite.ctx, "_any", "eth0", []string{"8.8.8.8"}, nil) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestUpdateDNSClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when client HTTP call fails returns error", + target: "_any", + iface: "eth0", + servers: []string{"8.8.8.8"}, + serverURL: "http://127.0.0.1:0", validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { suite.Error(err) suite.Nil(resp) suite.Contains(err.Error(), "update dns") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.UpdateDNS(suite.ctx, "_any", "eth0", []string{"8.8.8.8"}, nil) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestUpdateDNSNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], error) - }{ - { - name: "when server returns 202 with no JSON body returns UnexpectedStatusError", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { - suite.Error(err) - suite.Nil(resp) - - var target *osapi.UnexpectedStatusError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusAccepted, target.StatusCode) - suite.Equal("nil response body", target.Message) - }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusAccepted) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.UpdateDNS(suite.ctx, "_any", "eth0", []string{"8.8.8.8"}, nil) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestPing() { - tests := []struct { - name string - target string - address string - validateFunc func(*osapi.Response[osapi.Collection[osapi.PingResult]], error) - }{ - { - name: "when pinging address returns results", - target: "_any", - address: "8.8.8.8", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.PingResult]], err error) { - suite.NoError(err) - suite.NotNil(resp) - suite.Len(resp.Data.Results, 1) - suite.Equal("ping-host", resp.Data.Results[0].Hostname) - suite.Equal(4, resp.Data.Results[0].PacketsSent) - }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write( - []byte( - `{"results":[{"hostname":"ping-host","packets_sent":4,"packets_received":4,"packet_loss":0.0}]}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Ping(suite.ctx, tc.target, tc.address) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestPingError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.PingResult]], error) - }{ - { - name: "when server returns 403 returns AuthError", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.PingResult]], err error) { - suite.Error(err) - suite.Nil(resp) - - var target *osapi.AuthError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusForbidden, target.StatusCode) - }, - }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write([]byte(`{"error":"forbidden"}`)) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Ping(suite.ctx, "_any", "8.8.8.8") - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestPingClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.PingResult]], error) - }{ { - name: "when client HTTP call fails returns error", - validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.PingResult]], err error) { + name: "when server returns 202 with no JSON body returns UnexpectedStatusError", + target: "_any", + iface: "eth0", + servers: []string{"8.8.8.8"}, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusAccepted) + }, + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.DNSUpdateResult]], err error) { suite.Error(err) suite.Nil(resp) - suite.Contains(err.Error(), "ping") + + var target *osapi.UnexpectedStatusError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusAccepted, target.StatusCode) + suite.Equal("nil response body", target.Message) }, }, } for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), + var ( + serverURL string + cleanup func() ) - server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Ping(suite.ctx, "_any", "8.8.8.8") + resp, err := sut.Node.UpdateDNS( + suite.ctx, + tc.target, + tc.iface, + tc.servers, + tc.searchDomains, + ) tc.validateFunc(resp, err) }) } } -func (suite *NodePublicTestSuite) TestPingNilResponse() { +func (suite *NodePublicTestSuite) TestPing() { tests := []struct { name string + handler http.HandlerFunc + serverURL string + target string + address string validateFunc func(*osapi.Response[osapi.Collection[osapi.PingResult]], error) }{ { - name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + name: "when pinging address returns results", + target: "_any", + address: "8.8.8.8", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"ping-host","packets_sent":4,"packets_received":4,"packet_loss":0.0}]}`, + ), + ) + }, + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.PingResult]], err error) { + suite.NoError(err) + suite.NotNil(resp) + suite.Len(resp.Data.Results, 1) + suite.Equal("ping-host", resp.Data.Results[0].Hostname) + suite.Equal(4, resp.Data.Results[0].PacketsSent) + }, + }, + { + name: "when server returns 403 returns AuthError", + target: "_any", + address: "8.8.8.8", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte(`{"error":"forbidden"}`)) + }, + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.PingResult]], err error) { + suite.Error(err) + suite.Nil(resp) + + var target *osapi.AuthError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusForbidden, target.StatusCode) + }, + }, + { + name: "when client HTTP call fails returns error", + target: "_any", + address: "8.8.8.8", + serverURL: "http://127.0.0.1:0", + validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.PingResult]], err error) { + suite.Error(err) + suite.Nil(resp) + suite.Contains(err.Error(), "ping") + }, + }, + { + name: "when server returns 200 with no JSON body returns UnexpectedStatusError", + target: "_any", + address: "8.8.8.8", + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.PingResult]], err error) { suite.Error(err) suite.Nil(resp) @@ -1655,20 +1096,28 @@ func (suite *NodePublicTestSuite) TestPingNilResponse() { for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Ping(suite.ctx, "_any", "8.8.8.8") + resp, err := sut.Node.Ping(suite.ctx, tc.target, tc.address) tc.validateFunc(resp, err) }) } @@ -1677,6 +1126,8 @@ func (suite *NodePublicTestSuite) TestPingNilResponse() { func (suite *NodePublicTestSuite) TestExec() { tests := []struct { name string + handler http.HandlerFunc + serverURL string req osapi.ExecRequest validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) }{ @@ -1686,6 +1137,15 @@ func (suite *NodePublicTestSuite) TestExec() { Command: "whoami", Target: "_any", }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"exec-host","stdout":"root\n","exit_code":0,"changed":true}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -1704,158 +1164,97 @@ func (suite *NodePublicTestSuite) TestExec() { Timeout: 10, Target: "_any", }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"exec-host","stdout":"root\n","exit_code":0,"changed":true}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.NoError(err) suite.NotNil(resp) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusAccepted) - _, _ = w.Write( - []byte( - `{"results":[{"hostname":"exec-host","stdout":"root\n","exit_code":0,"changed":true}]}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Exec(suite.ctx, tc.req) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestExecClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when server returns 400 returns ValidationError", + req: osapi.ExecRequest{ + Target: "_any", + }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(`{"error":"command is required"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.Error(err) suite.Nil(resp) - suite.Contains(err.Error(), "exec command") + + var target *osapi.ValidationError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusBadRequest, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Exec(suite.ctx, osapi.ExecRequest{ + { + name: "when client HTTP call fails returns error", + serverURL: "http://127.0.0.1:0", + req: osapi.ExecRequest{ Command: "whoami", Target: "_any", - }) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestExecNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) - }{ - { - name: "when server returns 202 with no JSON body returns UnexpectedStatusError", + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.Error(err) suite.Nil(resp) - - var target *osapi.UnexpectedStatusError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusAccepted, target.StatusCode) - suite.Equal("nil response body", target.Message) + suite.Contains(err.Error(), "exec command") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusAccepted) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Exec(suite.ctx, osapi.ExecRequest{ + { + name: "when server returns 202 with no JSON body returns UnexpectedStatusError", + req: osapi.ExecRequest{ Command: "whoami", Target: "_any", - }) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestExecError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) - }{ - { - name: "when server returns 400 returns ValidationError", + }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusAccepted) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.Error(err) suite.Nil(resp) - var target *osapi.ValidationError + var target *osapi.UnexpectedStatusError suite.True(errors.As(err, &target)) - suite.Equal(http.StatusBadRequest, target.StatusCode) + suite.Equal(http.StatusAccepted, target.StatusCode) + suite.Equal("nil response body", target.Message) }, }, } for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(`{"error":"command is required"}`)) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Exec(suite.ctx, osapi.ExecRequest{ - Target: "_any", - }) + resp, err := sut.Node.Exec(suite.ctx, tc.req) tc.validateFunc(resp, err) }) } @@ -1864,6 +1263,8 @@ func (suite *NodePublicTestSuite) TestExecError() { func (suite *NodePublicTestSuite) TestShell() { tests := []struct { name string + handler http.HandlerFunc + serverURL string req osapi.ShellRequest validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) }{ @@ -1873,6 +1274,15 @@ func (suite *NodePublicTestSuite) TestShell() { Command: "uname -a", Target: "_any", }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"shell-host","exit_code":0,"changed":false}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.NoError(err) suite.NotNil(resp) @@ -1888,158 +1298,97 @@ func (suite *NodePublicTestSuite) TestShell() { Timeout: 15, Target: "_any", }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write( + []byte( + `{"results":[{"hostname":"shell-host","exit_code":0,"changed":false}]}`, + ), + ) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.NoError(err) suite.NotNil(resp) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusAccepted) - _, _ = w.Write( - []byte( - `{"results":[{"hostname":"shell-host","exit_code":0,"changed":false}]}`, - ), - ) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Shell(suite.ctx, tc.req) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestShellClientError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) - }{ { - name: "when client HTTP call fails returns error", + name: "when server returns 400 returns ValidationError", + req: osapi.ShellRequest{ + Target: "_any", + }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(`{"error":"command is required"}`)) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.Error(err) suite.Nil(resp) - suite.Contains(err.Error(), "shell command") + + var target *osapi.ValidationError + suite.True(errors.As(err, &target)) + suite.Equal(http.StatusBadRequest, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}), - ) - server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Shell(suite.ctx, osapi.ShellRequest{ + { + name: "when client HTTP call fails returns error", + serverURL: "http://127.0.0.1:0", + req: osapi.ShellRequest{ Command: "uname -a", Target: "_any", - }) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestShellNilResponse() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) - }{ - { - name: "when server returns 202 with no JSON body returns UnexpectedStatusError", + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.Error(err) suite.Nil(resp) - - var target *osapi.UnexpectedStatusError - suite.True(errors.As(err, &target)) - suite.Equal(http.StatusAccepted, target.StatusCode) - suite.Equal("nil response body", target.Message) + suite.Contains(err.Error(), "shell command") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusAccepted) - }), - ) - defer server.Close() - - sut := osapi.New( - server.URL, - "test-token", - osapi.WithLogger(slog.Default()), - ) - - resp, err := sut.Node.Shell(suite.ctx, osapi.ShellRequest{ + { + name: "when server returns 202 with no JSON body returns UnexpectedStatusError", + req: osapi.ShellRequest{ Command: "uname -a", Target: "_any", - }) - tc.validateFunc(resp, err) - }) - } -} - -func (suite *NodePublicTestSuite) TestShellError() { - tests := []struct { - name string - validateFunc func(*osapi.Response[osapi.Collection[osapi.CommandResult]], error) - }{ - { - name: "when server returns 400 returns ValidationError", + }, + handler: func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusAccepted) + }, validateFunc: func(resp *osapi.Response[osapi.Collection[osapi.CommandResult]], err error) { suite.Error(err) suite.Nil(resp) - var target *osapi.ValidationError + var target *osapi.UnexpectedStatusError suite.True(errors.As(err, &target)) - suite.Equal(http.StatusBadRequest, target.StatusCode) + suite.Equal(http.StatusAccepted, target.StatusCode) + suite.Equal("nil response body", target.Message) }, }, } for _, tc := range tests { suite.Run(tc.name, func() { - server := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(`{"error":"command is required"}`)) - }), + var ( + serverURL string + cleanup func() ) - defer server.Close() + + if tc.serverURL != "" { + serverURL = tc.serverURL + cleanup = func() {} + } else { + server := httptest.NewServer(tc.handler) + serverURL = server.URL + cleanup = server.Close + } + defer cleanup() sut := osapi.New( - server.URL, + serverURL, "test-token", osapi.WithLogger(slog.Default()), ) - resp, err := sut.Node.Shell(suite.ctx, osapi.ShellRequest{ - Target: "_any", - }) + resp, err := sut.Node.Shell(suite.ctx, tc.req) tc.validateFunc(resp, err) }) } diff --git a/pkg/osapi/osapi_public_test.go b/pkg/osapi/osapi_public_test.go index fc1f1e3..188283b 100644 --- a/pkg/osapi/osapi_public_test.go +++ b/pkg/osapi/osapi_public_test.go @@ -54,10 +54,14 @@ func (suite *ClientPublicTestSuite) TearDownTest() { func (suite *ClientPublicTestSuite) TestNew() { tests := []struct { name string + opts func() []osapi.Option validateFunc func(*osapi.Client) }{ { name: "when creating client returns all services", + opts: func() []osapi.Option { + return nil + }, validateFunc: func(c *osapi.Client) { suite.NotNil(c) suite.NotNil(c.Node) @@ -67,23 +71,14 @@ func (suite *ClientPublicTestSuite) TestNew() { suite.NotNil(c.Metrics) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - c := osapi.New(suite.server.URL, "test-token") - tc.validateFunc(c) - }) - } -} - -func (suite *ClientPublicTestSuite) TestNewWithHTTPTransport() { - tests := []struct { - name string - validateFunc func(*osapi.Client) - }{ { name: "when custom transport provided creates client", + opts: func() []osapi.Option { + return []osapi.Option{ + osapi.WithHTTPTransport(&http.Transport{}), + osapi.WithLogger(slog.Default()), + } + }, validateFunc: func(c *osapi.Client) { suite.NotNil(c) }, @@ -92,18 +87,14 @@ func (suite *ClientPublicTestSuite) TestNewWithHTTPTransport() { for _, tc := range tests { suite.Run(tc.name, func() { - customTransport := &http.Transport{} - c := osapi.New( - suite.server.URL, - "test-token", - osapi.WithHTTPTransport(customTransport), - osapi.WithLogger(slog.Default()), - ) + c := osapi.New(suite.server.URL, "test-token", tc.opts()...) tc.validateFunc(c) }) } } -func TestClientPublicTestSuite(t *testing.T) { +func TestClientPublicTestSuite( + t *testing.T, +) { suite.Run(t, new(ClientPublicTestSuite)) } diff --git a/pkg/osapi/response.go b/pkg/osapi/response.go index 8ee4e96..59987fc 100644 --- a/pkg/osapi/response.go +++ b/pkg/osapi/response.go @@ -70,6 +70,8 @@ func checkError( return &AuthError{APIError{StatusCode: statusCode, Message: msg}} case 404: return &NotFoundError{APIError{StatusCode: statusCode, Message: msg}} + case 409: + return &ConflictError{APIError{StatusCode: statusCode, Message: msg}} case 500: return &ServerError{APIError{StatusCode: statusCode, Message: msg}} default: diff --git a/pkg/osapi/response_test.go b/pkg/osapi/response_test.go index b5ad950..3d14331 100644 --- a/pkg/osapi/response_test.go +++ b/pkg/osapi/response_test.go @@ -33,73 +33,55 @@ type ResponseTestSuite struct { suite.Suite } -func (suite *ResponseTestSuite) TestCheckErrorSuccess() { +func (suite *ResponseTestSuite) TestCheckError() { tests := []struct { - name string - statusCode int + name string + statusCode int + validateFunc func(error) }{ { name: "when status is 200", statusCode: 200, + validateFunc: func(err error) { + suite.NoError(err) + }, }, { name: "when status is 201", statusCode: 201, + validateFunc: func(err error) { + suite.NoError(err) + }, }, { name: "when status is 202", statusCode: 202, + validateFunc: func(err error) { + suite.NoError(err) + }, }, { name: "when status is 204", statusCode: 204, + validateFunc: func(err error) { + suite.NoError(err) + }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - err := checkError(tc.statusCode) - suite.NoError(err) - }) - } -} - -func (suite *ResponseTestSuite) TestCheckErrorValidation() { - tests := []struct { - name string - statusCode int - validateFunc func(error) - }{ { name: "when status is 400", statusCode: 400, validateFunc: func(err error) { + suite.Error(err) var target *ValidationError suite.True(errors.As(err, &target)) suite.Equal(400, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - err := checkError(tc.statusCode) - suite.Error(err) - tc.validateFunc(err) - }) - } -} - -func (suite *ResponseTestSuite) TestCheckErrorAuth() { - tests := []struct { - name string - statusCode int - validateFunc func(error) - }{ { name: "when status is 401", statusCode: 401, validateFunc: func(err error) { + suite.Error(err) var target *AuthError suite.True(errors.As(err, &target)) suite.Equal(401, target.StatusCode) @@ -109,84 +91,47 @@ func (suite *ResponseTestSuite) TestCheckErrorAuth() { name: "when status is 403", statusCode: 403, validateFunc: func(err error) { + suite.Error(err) var target *AuthError suite.True(errors.As(err, &target)) suite.Equal(403, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - err := checkError(tc.statusCode) - suite.Error(err) - tc.validateFunc(err) - }) - } -} - -func (suite *ResponseTestSuite) TestCheckErrorNotFound() { - tests := []struct { - name string - statusCode int - validateFunc func(error) - }{ { name: "when status is 404", statusCode: 404, validateFunc: func(err error) { + suite.Error(err) var target *NotFoundError suite.True(errors.As(err, &target)) suite.Equal(404, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - err := checkError(tc.statusCode) - suite.Error(err) - tc.validateFunc(err) - }) - } -} - -func (suite *ResponseTestSuite) TestCheckErrorServer() { - tests := []struct { - name string - statusCode int - validateFunc func(error) - }{ + { + name: "when status is 409", + statusCode: 409, + validateFunc: func(err error) { + suite.Error(err) + var target *ConflictError + suite.True(errors.As(err, &target)) + suite.Equal(409, target.StatusCode) + }, + }, { name: "when status is 500", statusCode: 500, validateFunc: func(err error) { + suite.Error(err) var target *ServerError suite.True(errors.As(err, &target)) suite.Equal(500, target.StatusCode) }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - err := checkError(tc.statusCode) - suite.Error(err) - tc.validateFunc(err) - }) - } -} - -func (suite *ResponseTestSuite) TestCheckErrorUnexpected() { - tests := []struct { - name string - statusCode int - validateFunc func(error) - }{ { name: "when status is 503", statusCode: 503, validateFunc: func(err error) { + suite.Error(err) var target *UnexpectedStatusError suite.True(errors.As(err, &target)) suite.Equal(503, target.StatusCode) @@ -197,13 +142,12 @@ func (suite *ResponseTestSuite) TestCheckErrorUnexpected() { for _, tc := range tests { suite.Run(tc.name, func() { err := checkError(tc.statusCode) - suite.Error(err) tc.validateFunc(err) }) } } -func (suite *ResponseTestSuite) TestCheckErrorWithMessage() { +func (suite *ResponseTestSuite) TestCheckErrorMessages() { tests := []struct { name string statusCode int @@ -218,32 +162,16 @@ func (suite *ResponseTestSuite) TestCheckErrorWithMessage() { return []*gen.ErrorResponse{{Error: &msg}} }(), validateFunc: func(err error) { + suite.Error(err) suite.Contains(err.Error(), "field 'name' is required") }, }, - } - - for _, tc := range tests { - suite.Run(tc.name, func() { - err := checkError(tc.statusCode, tc.responses...) - suite.Error(err) - tc.validateFunc(err) - }) - } -} - -func (suite *ResponseTestSuite) TestCheckErrorNilResponses() { - tests := []struct { - name string - statusCode int - responses []*gen.ErrorResponse - validateFunc func(error) - }{ { name: "when all responses are nil", statusCode: 400, responses: []*gen.ErrorResponse{nil, nil}, validateFunc: func(err error) { + suite.Error(err) suite.Contains(err.Error(), "unexpected status 400") }, }, @@ -252,6 +180,7 @@ func (suite *ResponseTestSuite) TestCheckErrorNilResponses() { statusCode: 500, responses: nil, validateFunc: func(err error) { + suite.Error(err) suite.Contains(err.Error(), "unexpected status 500") }, }, @@ -260,6 +189,7 @@ func (suite *ResponseTestSuite) TestCheckErrorNilResponses() { statusCode: 404, responses: []*gen.ErrorResponse{{Error: nil}}, validateFunc: func(err error) { + suite.Error(err) suite.Contains(err.Error(), "unexpected status 404") }, }, @@ -268,7 +198,6 @@ func (suite *ResponseTestSuite) TestCheckErrorNilResponses() { for _, tc := range tests { suite.Run(tc.name, func() { err := checkError(tc.statusCode, tc.responses...) - suite.Error(err) tc.validateFunc(err) }) } diff --git a/pkg/osapi/types.go b/pkg/osapi/types.go new file mode 100644 index 0000000..eae7db1 --- /dev/null +++ b/pkg/osapi/types.go @@ -0,0 +1,31 @@ +// Copyright (c) 2026 John Dewey + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +package osapi + +// TimelineEvent represents a lifecycle event. Used by both job +// timelines and agent state transition history. +type TimelineEvent struct { + Timestamp string + Event string + Hostname string + Message string + Error string +}