Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0236dff
[DPS-42278] added support for log destinations api + unit tests
akrzyszt Apr 21, 2026
1b6d151
[DPS-42278] integration tests + review tweaks
akrzyszt Apr 22, 2026
1632461
[DPS-42278] review tweaks
akrzyszt Apr 29, 2026
d1c4b94
[DPS-42278] removed time fields hack + updated fixtures + resolved is…
akrzyszt May 6, 2026
a9f60d4
[DPS-42278] more tests tweaks + new api changes
akrzyszt May 6, 2026
ee844ab
[DPS-42278] added support for custom https destination type
akrzyszt May 6, 2026
e1e577b
[DPS-42279] [ACLP SDK] [Go] ACLP Logs stream API
klipensk May 6, 2026
e0b4971
[DPS-42279] [ACLP SDK] [Go] ACLP Logs stream API - fixtures and fixes
klipensk May 7, 2026
e4cdb80
[DPS-42279] [ACLP SDK] [Go] ACLP Logs stream API - log destinations a…
klipensk May 7, 2026
6d80047
[DPS-42278] added support for log destinations api + unit tests
akrzyszt May 8, 2026
cfac7b9
[DPS-42279] [ACLP SDK] [Go] ACLP Logs stream API - regenerated fixtures
klipensk May 8, 2026
3225057
Merge branch 'main' into DPS-42279-aclp-logs-stream-api
klipensk May 8, 2026
967e158
[DPS-42279] [ACLP SDK] [Go] ACLP Logs stream API - regenerated fixtures
klipensk May 8, 2026
937b956
[DPS-42279] [ACLP SDK] [Go] ACLP Logs stream API - fix
klipensk May 11, 2026
50f8517
[DPS-42279] [ACLP SDK] [Go] ACLP Logs stream API - fixes regarding PR…
klipensk May 11, 2026
c1b131a
Merge pull request #4 from akrzyszt/DPS-42279-aclp-logs-stream-api
klipensk May 12, 2026
82b9398
[DPS-42654] [ACLP SDK][Go] ACLP Logs SDK Pull request - added github …
klipensk May 12, 2026
7e529c3
[DPS-42654] [ACLP SDK][Go] ACLP Logs SDK Pull request - added github …
klipensk May 12, 2026
7df8022
Merge remote-tracking branch 'upstream/main' into ACLP-LOGS-support
klipensk May 13, 2026
5e877ef
[DPS-42654] [ACLP SDK][Go] ACLP Logs SDK Pull request - fixed issues …
klipensk May 14, 2026
a0165ce
[DPS-42654] [ACLP SDK][Go] ACLP Logs SDK Pull request - fixed lint er…
klipensk May 15, 2026
6e47926
Potential fix for pull request finding
klipensk May 20, 2026
0c4d454
[DPS-42654] [ACLP SDK][Go] ACLP Logs SDK Pull request - lint errors
klipensk May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ name: Continuous Integration
on:
workflow_dispatch:
inputs:
run_aclp_logs_stream_tests:
description: 'Set this parameter to "true" to run ACLP logs stream related test cases'
required: false
default: 'false'
type: choice
options:
- 'true'
- 'false'
test_report_upload:
description: 'Indicates whether to upload the test report to object storage. Defaults to "false"'
type: choice
Expand Down Expand Up @@ -105,6 +113,7 @@ jobs:
make test | go-junit-report -set-exit-code -iocopy -out $REPORT_FILENAME
env:
SKIP_LINT: 1
RUN_ACLP_LOGS_STREAM_TESTS: ${{ github.event.inputs.run_aclp_logs_stream_tests }}

- name: Upload test results to bucket
if: always() && github.repository == 'linode/linodego' && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.test_report_upload == 'true'))
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/integration_tests_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ on:
pull_request:
workflow_dispatch:
inputs:
run_aclp_logs_stream_tests:
description: 'Set this parameter to "true" to run ACLP logs stream related test cases'
required: false
default: 'false'
type: choice
options:
- 'true'
- 'false'
sha:
description: 'The hash value of the commit.'
required: true
Expand Down Expand Up @@ -40,11 +48,13 @@ jobs:
if: ${{ inputs.module != '' && steps.disallowed-char-check.outputs.match == '' }}
env:
LINODE_TOKEN: ${{ secrets.DX_LINODE_TOKEN }}
RUN_ACLP_LOGS_STREAM_TESTS: ${{ github.event.inputs.run_aclp_logs_stream_tests }}

- run: make fixtures
if: ${{ inputs.module == '' }}
env:
LINODE_TOKEN: ${{ secrets.DX_LINODE_TOKEN }}
RUN_ACLP_LOGS_STREAM_TESTS: ${{ github.event.inputs.run_aclp_logs_stream_tests }}

- name: Get the hash value of the latest commit from the PR branch
uses: octokit/graphql-action@v2.x
Expand Down
208 changes: 208 additions & 0 deletions monitor_log_destinations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package linodego

import (
"context"
"encoding/json"
"time"

"github.com/linode/linodego/internal/parseabletime"
)

// LogsDestinationType represents the type of a logs destination.
type LogsDestinationType string

const (
LogsDestinationTypeAkamaiObjectStorage LogsDestinationType = "akamai_object_storage"
LogsDestinationTypeCustomHTTPS LogsDestinationType = "custom_https"
)

// LogsDestinationStatus represents the status of a logs destination.
type LogsDestinationStatus string

const (
LogsDestinationStatusActive LogsDestinationStatus = "active"
LogsDestinationStatusInactive LogsDestinationStatus = "inactive"
)

// LogsDestinationDetails represents the details block returned in a LogsDestination response.
// Fields are populated based on the destination type.
type LogsDestinationDetails struct {
// akamai_object_storage fields
AccessKeyID string `json:"access_key_id,omitempty"`
BucketName string `json:"bucket_name,omitempty"`
Host string `json:"host,omitempty"`
Path string `json:"path,omitempty"`

// custom_https fields
EndpointURL string `json:"endpoint_url,omitempty"`
Authentication *LogsDestinationCustomHTTPSAuthDetails `json:"authentication,omitempty"`
ClientCertificateDetails *LogsDestinationClientCertificateDetails `json:"client_certificate_details,omitempty"`
ContentType string `json:"content_type,omitempty"`
CustomHeaders []LogsDestinationCustomHTTPSHeader `json:"custom_headers,omitempty"`
DataCompression string `json:"data_compression,omitempty"`
}

// LogsDestinationDetailsCreateOptions represents the details block used when creating
// an akamai_object_storage LogsDestination.
type LogsDestinationDetailsCreateOptions struct {
AccessKeyID string `json:"access_key_id"`
AccessKeySecret string `json:"access_key_secret"`
BucketName string `json:"bucket_name"`
Host string `json:"host"`
Path *string `json:"path,omitempty"`
}

// LogsDestinationCustomHTTPSAuthType represents the authentication type for a custom_https destination.
type LogsDestinationCustomHTTPSAuthType string

const (
LogsDestinationCustomHTTPSAuthTypeBasic LogsDestinationCustomHTTPSAuthType = "basic"
LogsDestinationCustomHTTPSAuthTypeNone LogsDestinationCustomHTTPSAuthType = "none"
)

// LogsDestinationCustomHTTPSBasicAuthDetails holds credentials for basic authentication.
// Both fields are required when authentication type is "basic".
type LogsDestinationCustomHTTPSBasicAuthDetails struct {
Username string `json:"basic_authentication_user"`
Password string `json:"basic_authentication_password"`
}

// LogsDestinationCustomHTTPSAuthDetails holds authentication configuration for a custom_https destination.
type LogsDestinationCustomHTTPSAuthDetails struct {
Type LogsDestinationCustomHTTPSAuthType `json:"type"`
Details *LogsDestinationCustomHTTPSBasicAuthDetails `json:"details,omitempty"`
}

// LogsDestinationCustomHTTPSHeader represents a single custom HTTP header.
type LogsDestinationCustomHTTPSHeader struct {
Name string `json:"name"`
Value string `json:"value"`
}

// LogsDestinationClientCertificateDetails contains TLS client certificate information
type LogsDestinationClientCertificateDetails struct {
ClientCACertificate string `json:"client_ca_certificate"`
ClientCertificate string `json:"client_certificate"`
ClientPrivateKey string `json:"client_private_key"`
TLSHostname string `json:"tls_hostname"`
}

// LogsDestinationCustomHTTPSDetailsCreateOptions represents the details block used when
// creating a custom_https LogsDestination.
type LogsDestinationCustomHTTPSDetailsCreateOptions struct {
EndpointURL string `json:"endpoint_url"`
Authentication *LogsDestinationCustomHTTPSAuthDetails `json:"authentication"`
ClientCertificateDetails *LogsDestinationClientCertificateDetails `json:"client_certificate_details,omitempty"`
ContentType string `json:"content_type,omitempty"`
CustomHeaders []LogsDestinationCustomHTTPSHeader `json:"custom_headers,omitempty"`
DataCompression string `json:"data_compression,omitempty"`
}

// LogsDestination represents a logs destination object.
type LogsDestination struct {
Created *time.Time `json:"-"`
CreatedBy string `json:"created_by"`
Details LogsDestinationDetails `json:"details"`
ID int `json:"id"`
Label string `json:"label"`
Status LogsDestinationStatus `json:"status"`
Type LogsDestinationType `json:"type"`
Updated *time.Time `json:"-"`
UpdatedBy string `json:"updated_by"`
Version int `json:"version"`
}

// UnmarshalJSON implements the json.Unmarshaler interface for LogsDestination.
func (i *LogsDestination) UnmarshalJSON(b []byte) error {
type Mask LogsDestination

p := struct {
*Mask

Created *parseabletime.ParseableTime `json:"created"`
Updated *parseabletime.ParseableTime `json:"updated"`
}{
Mask: (*Mask)(i),
}

if err := json.Unmarshal(b, &p); err != nil {
return err
}

i.Created = (*time.Time)(p.Created)
i.Updated = (*time.Time)(p.Updated)

return nil
}

const logsDestinationBaseEndpoint = "monitor/streams/destinations"

// LogsDestinationCreateOptions are the options used to create a new logs destination.
type LogsDestinationCreateOptions struct {
Label string `json:"label"`
Type LogsDestinationType `json:"type"`
Details any `json:"details"`
}

// LogsDestinationDetailsUpdateOptions represents the details block used when updating
// an akamai_object_storage LogsDestination.
type LogsDestinationDetailsUpdateOptions struct {
AccessKeyID string `json:"access_key_id,omitempty"`
AccessKeySecret string `json:"access_key_secret,omitempty"`
BucketName string `json:"bucket_name,omitempty"`
Host string `json:"host,omitempty"`
Path *string `json:"path,omitempty"`
}

// LogsDestinationCustomHTTPSDetailsUpdateOptions represents the details block used when
// updating a custom_https LogsDestination.
type LogsDestinationCustomHTTPSDetailsUpdateOptions struct {
EndpointURL string `json:"endpoint_url,omitempty"`
Authentication *LogsDestinationCustomHTTPSAuthDetails `json:"authentication,omitempty"`
ClientCertificateDetails *LogsDestinationClientCertificateDetails `json:"client_certificate_details,omitempty"`
ContentType string `json:"content_type,omitempty"`
CustomHeaders []LogsDestinationCustomHTTPSHeader `json:"custom_headers,omitempty"`
DataCompression string `json:"data_compression,omitempty"`
}

// LogsDestinationUpdateOptions are the options used to update a LogsDestination.
// Set Details to *LogsDestinationDetailsUpdateOptions for akamai_object_storage,
// or *LogsDestinationCustomHTTPSDetailsUpdateOptions for custom_https.
type LogsDestinationUpdateOptions struct {
Label string `json:"label,omitempty"`
Details any `json:"details,omitempty"`
}

// ListLogsDestinations returns a paginated list of logs destinations.
func (c *Client) ListLogsDestinations(ctx context.Context, opts *ListOptions) ([]LogsDestination, error) {
return getPaginatedResults[LogsDestination](ctx, c, logsDestinationBaseEndpoint, opts)
}

// GetLogsDestination gets a single logs destination by ID.
func (c *Client) GetLogsDestination(ctx context.Context, destinationID int) (*LogsDestination, error) {
e := formatAPIPath(logsDestinationBaseEndpoint+"/%d", destinationID)
return doGETRequest[LogsDestination](ctx, c, e)
}

// CreateLogsDestination creates a new logs destination.
func (c *Client) CreateLogsDestination(ctx context.Context, opts LogsDestinationCreateOptions) (*LogsDestination, error) {
return doPOSTRequest[LogsDestination](ctx, c, logsDestinationBaseEndpoint, opts)
}

// UpdateLogsDestination updates a logs destination.
func (c *Client) UpdateLogsDestination(ctx context.Context, destinationID int, opts LogsDestinationUpdateOptions) (*LogsDestination, error) {
e := formatAPIPath(logsDestinationBaseEndpoint+"/%d", destinationID)
return doPUTRequest[LogsDestination](ctx, c, e, opts)
}

// DeleteLogsDestination deletes a logs destination.
func (c *Client) DeleteLogsDestination(ctx context.Context, destinationID int) error {
e := formatAPIPath(logsDestinationBaseEndpoint+"/%d", destinationID)
return doDELETERequest(ctx, c, e)
}

// ListLogsDestinationHistory returns the version history for a logs destination.
func (c *Client) ListLogsDestinationHistory(ctx context.Context, destinationID int, opts *ListOptions) ([]LogsDestination, error) {
e := formatAPIPath(logsDestinationBaseEndpoint+"/%d/history", destinationID)
return getPaginatedResults[LogsDestination](ctx, c, e, opts)
}
Loading
Loading