dnscontrol/pkg/cloudflare-go/logpush.go
Tom Limoncelli 7fd6a74e0c
CLOUDFLAREAPI: CF_REDIRECT/CF_TEMP_REDIRECT should dtrt using Single Redirects (#3002)
Co-authored-by: Josh Zhang <jzhang1@stackoverflow.com>
2024-06-18 17:38:50 -04:00

573 lines
18 KiB
Go

package cloudflare
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"github.com/goccy/go-json"
)
// LogpushJob describes a Logpush job.
type LogpushJob struct {
ID int `json:"id,omitempty"`
Dataset string `json:"dataset"`
Enabled bool `json:"enabled"`
Kind string `json:"kind,omitempty"`
Name string `json:"name"`
LogpullOptions string `json:"logpull_options,omitempty"`
OutputOptions *LogpushOutputOptions `json:"output_options,omitempty"`
DestinationConf string `json:"destination_conf"`
OwnershipChallenge string `json:"ownership_challenge,omitempty"`
LastComplete *time.Time `json:"last_complete,omitempty"`
LastError *time.Time `json:"last_error,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
Frequency string `json:"frequency,omitempty"`
Filter *LogpushJobFilters `json:"filter,omitempty"`
MaxUploadBytes int `json:"max_upload_bytes,omitempty"`
MaxUploadRecords int `json:"max_upload_records,omitempty"`
MaxUploadIntervalSeconds int `json:"max_upload_interval_seconds,omitempty"`
}
type LogpushJobFilters struct {
Where LogpushJobFilter `json:"where"`
}
type Operator string
const (
Equal Operator = "eq"
NotEqual Operator = "!eq"
LessThan Operator = "lt"
LessThanOrEqual Operator = "leq"
GreaterThan Operator = "gt"
GreaterThanOrEqual Operator = "geq"
StartsWith Operator = "startsWith"
EndsWith Operator = "endsWith"
NotStartsWith Operator = "!startsWith"
NotEndsWith Operator = "!endsWith"
Contains Operator = "contains"
NotContains Operator = "!contains"
ValueIsIn Operator = "in"
ValueIsNotIn Operator = "!in"
)
type LogpushJobFilter struct {
// either this
And []LogpushJobFilter `json:"and,omitempty"`
Or []LogpushJobFilter `json:"or,omitempty"`
// or this
Key string `json:"key,omitempty"`
Operator Operator `json:"operator,omitempty"`
Value interface{} `json:"value,omitempty"`
}
type LogpushOutputOptions struct {
FieldNames []string `json:"field_names"`
OutputType string `json:"output_type,omitempty"`
BatchPrefix string `json:"batch_prefix,omitempty"`
BatchSuffix string `json:"batch_suffix,omitempty"`
RecordPrefix string `json:"record_prefix,omitempty"`
RecordSuffix string `json:"record_suffix,omitempty"`
RecordTemplate string `json:"record_template,omitempty"`
RecordDelimiter string `json:"record_delimiter,omitempty"`
FieldDelimiter string `json:"field_delimiter,omitempty"`
TimestampFormat string `json:"timestamp_format,omitempty"`
SampleRate float64 `json:"sample_rate,omitempty"`
CVE202144228 *bool `json:"CVE-2021-44228,omitempty"`
}
// LogpushJobsResponse is the API response, containing an array of Logpush Jobs.
type LogpushJobsResponse struct {
Response
Result []LogpushJob `json:"result"`
}
// LogpushJobDetailsResponse is the API response, containing a single Logpush Job.
type LogpushJobDetailsResponse struct {
Response
Result LogpushJob `json:"result"`
}
// LogpushFieldsResponse is the API response for a datasets fields.
type LogpushFieldsResponse struct {
Response
Result LogpushFields `json:"result"`
}
// LogpushFields is a map of available Logpush field names & descriptions.
type LogpushFields map[string]string
// LogpushGetOwnershipChallenge describes a ownership validation.
type LogpushGetOwnershipChallenge struct {
Filename string `json:"filename"`
Valid bool `json:"valid"`
Message string `json:"message"`
}
// LogpushGetOwnershipChallengeResponse is the API response, containing a ownership challenge.
type LogpushGetOwnershipChallengeResponse struct {
Response
Result LogpushGetOwnershipChallenge `json:"result"`
}
// LogpushGetOwnershipChallengeRequest is the API request for get ownership challenge.
type LogpushGetOwnershipChallengeRequest struct {
DestinationConf string `json:"destination_conf"`
}
// LogpushOwnershipChallengeValidationResponse is the API response,
// containing a ownership challenge validation result.
type LogpushOwnershipChallengeValidationResponse struct {
Response
Result struct {
Valid bool `json:"valid"`
}
}
// LogpushValidateOwnershipChallengeRequest is the API request for validate ownership challenge.
type LogpushValidateOwnershipChallengeRequest struct {
DestinationConf string `json:"destination_conf"`
OwnershipChallenge string `json:"ownership_challenge"`
}
// LogpushDestinationExistsResponse is the API response,
// containing a destination exists check result.
type LogpushDestinationExistsResponse struct {
Response
Result struct {
Exists bool `json:"exists"`
}
}
// LogpushDestinationExistsRequest is the API request for check destination exists.
type LogpushDestinationExistsRequest struct {
DestinationConf string `json:"destination_conf"`
}
// Custom Marshaller for LogpushJob filter key.
func (f LogpushJob) MarshalJSON() ([]byte, error) {
type Alias LogpushJob
var filter string
if f.Filter != nil {
b, err := json.Marshal(f.Filter)
if err != nil {
return nil, err
}
filter = string(b)
}
return json.Marshal(&struct {
Filter string `json:"filter,omitempty"`
Alias
}{
Filter: filter,
Alias: (Alias)(f),
})
}
// Custom Unmarshaller for LogpushJob filter key.
func (f *LogpushJob) UnmarshalJSON(data []byte) error {
type Alias LogpushJob
aux := &struct {
Filter string `json:"filter,omitempty"`
*Alias
}{
Alias: (*Alias)(f),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux != nil && aux.Filter != "" {
var filter LogpushJobFilters
if err := json.Unmarshal([]byte(aux.Filter), &filter); err != nil {
return err
}
if err := filter.Where.Validate(); err != nil {
return err
}
f.Filter = &filter
}
return nil
}
func (f CreateLogpushJobParams) MarshalJSON() ([]byte, error) {
type Alias CreateLogpushJobParams
var filter string
if f.Filter != nil {
b, err := json.Marshal(f.Filter)
if err != nil {
return nil, err
}
filter = string(b)
}
return json.Marshal(&struct {
Filter string `json:"filter,omitempty"`
Alias
}{
Filter: filter,
Alias: (Alias)(f),
})
}
// Custom Unmarshaller for CreateLogpushJobParams filter key.
func (f *CreateLogpushJobParams) UnmarshalJSON(data []byte) error {
type Alias CreateLogpushJobParams
aux := &struct {
Filter string `json:"filter,omitempty"`
*Alias
}{
Alias: (*Alias)(f),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux != nil && aux.Filter != "" {
var filter LogpushJobFilters
if err := json.Unmarshal([]byte(aux.Filter), &filter); err != nil {
return err
}
if err := filter.Where.Validate(); err != nil {
return err
}
f.Filter = &filter
}
return nil
}
func (f UpdateLogpushJobParams) MarshalJSON() ([]byte, error) {
type Alias UpdateLogpushJobParams
var filter string
if f.Filter != nil {
b, err := json.Marshal(f.Filter)
if err != nil {
return nil, err
}
filter = string(b)
}
return json.Marshal(&struct {
Filter string `json:"filter,omitempty"`
Alias
}{
Filter: filter,
Alias: (Alias)(f),
})
}
// Custom Unmarshaller for UpdateLogpushJobParams filter key.
func (f *UpdateLogpushJobParams) UnmarshalJSON(data []byte) error {
type Alias UpdateLogpushJobParams
aux := &struct {
Filter string `json:"filter,omitempty"`
*Alias
}{
Alias: (*Alias)(f),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux != nil && aux.Filter != "" {
var filter LogpushJobFilters
if err := json.Unmarshal([]byte(aux.Filter), &filter); err != nil {
return err
}
if err := filter.Where.Validate(); err != nil {
return err
}
f.Filter = &filter
}
return nil
}
func (filter *LogpushJobFilter) Validate() error {
if filter.And != nil {
if filter.Or != nil || filter.Key != "" || filter.Operator != "" || filter.Value != nil {
return errors.New("And can't be set with Or, Key, Operator or Value")
}
for i, element := range filter.And {
err := element.Validate()
if err != nil {
return fmt.Errorf("element %v in And is invalid: %w", i, err)
}
}
return nil
}
if filter.Or != nil {
if filter.And != nil || filter.Key != "" || filter.Operator != "" || filter.Value != nil {
return errors.New("Or can't be set with And, Key, Operator or Value")
}
for i, element := range filter.Or {
err := element.Validate()
if err != nil {
return fmt.Errorf("element %v in Or is invalid: %w", i, err)
}
}
return nil
}
if filter.Key == "" {
return errors.New("Key is missing")
}
if filter.Operator == "" {
return errors.New("Operator is missing")
}
if filter.Value == nil {
return errors.New("Value is missing")
}
return nil
}
type CreateLogpushJobParams struct {
Dataset string `json:"dataset"`
Enabled bool `json:"enabled"`
Kind string `json:"kind,omitempty"`
Name string `json:"name"`
LogpullOptions string `json:"logpull_options,omitempty"`
OutputOptions *LogpushOutputOptions `json:"output_options,omitempty"`
DestinationConf string `json:"destination_conf"`
OwnershipChallenge string `json:"ownership_challenge,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
Frequency string `json:"frequency,omitempty"`
Filter *LogpushJobFilters `json:"filter,omitempty"`
MaxUploadBytes int `json:"max_upload_bytes,omitempty"`
MaxUploadRecords int `json:"max_upload_records,omitempty"`
MaxUploadIntervalSeconds int `json:"max_upload_interval_seconds,omitempty"`
}
type ListLogpushJobsParams struct{}
type ListLogpushJobsForDatasetParams struct {
Dataset string `json:"-"`
}
type GetLogpushFieldsParams struct {
Dataset string `json:"-"`
}
type UpdateLogpushJobParams struct {
ID int `json:"-"`
Dataset string `json:"dataset"`
Enabled bool `json:"enabled"`
Kind string `json:"kind,omitempty"`
Name string `json:"name"`
LogpullOptions string `json:"logpull_options,omitempty"`
OutputOptions *LogpushOutputOptions `json:"output_options,omitempty"`
DestinationConf string `json:"destination_conf"`
OwnershipChallenge string `json:"ownership_challenge,omitempty"`
LastComplete *time.Time `json:"last_complete,omitempty"`
LastError *time.Time `json:"last_error,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
Frequency string `json:"frequency,omitempty"`
Filter *LogpushJobFilters `json:"filter,omitempty"`
MaxUploadBytes int `json:"max_upload_bytes,omitempty"`
MaxUploadRecords int `json:"max_upload_records,omitempty"`
MaxUploadIntervalSeconds int `json:"max_upload_interval_seconds,omitempty"`
}
type ValidateLogpushOwnershipChallengeParams struct {
DestinationConf string `json:"destination_conf"`
OwnershipChallenge string `json:"ownership_challenge"`
}
type GetLogpushOwnershipChallengeParams struct {
DestinationConf string `json:"destination_conf"`
}
// CreateLogpushJob creates a new zone-level Logpush Job.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-create-logpush-job
func (api *API) CreateLogpushJob(ctx context.Context, rc *ResourceContainer, params CreateLogpushJobParams) (*LogpushJob, error) {
uri := fmt.Sprintf("/%s/%s/logpush/jobs", rc.Level, rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
if err != nil {
return nil, err
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return &r.Result, nil
}
// ListAccountLogpushJobs returns all Logpush Jobs for all datasets.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-list-logpush-jobs
func (api *API) ListLogpushJobs(ctx context.Context, rc *ResourceContainer, params ListLogpushJobsParams) ([]LogpushJob, error) {
uri := fmt.Sprintf("/%s/%s/logpush/jobs", rc.Level, rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return []LogpushJob{}, err
}
var r LogpushJobsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []LogpushJob{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// LogpushJobsForDataset returns all Logpush Jobs for a dataset.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-list-logpush-jobs-for-a-dataset
func (api *API) ListLogpushJobsForDataset(ctx context.Context, rc *ResourceContainer, params ListLogpushJobsForDatasetParams) ([]LogpushJob, error) {
uri := fmt.Sprintf("/%s/%s/logpush/datasets/%s/jobs", rc.Level, rc.Identifier, params.Dataset)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return []LogpushJob{}, err
}
var r LogpushJobsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []LogpushJob{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// LogpushFields returns fields for a given dataset.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-list-logpush-jobs
func (api *API) GetLogpushFields(ctx context.Context, rc *ResourceContainer, params GetLogpushFieldsParams) (LogpushFields, error) {
uri := fmt.Sprintf("/%s/%s/logpush/datasets/%s/fields", rc.Level, rc.Identifier, params.Dataset)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return LogpushFields{}, err
}
var r LogpushFieldsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return LogpushFields{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// LogpushJob fetches detail about one Logpush Job for a zone.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-logpush-job-details
func (api *API) GetLogpushJob(ctx context.Context, rc *ResourceContainer, jobID int) (LogpushJob, error) {
uri := fmt.Sprintf("/%s/%s/logpush/jobs/%d", rc.Level, rc.Identifier, jobID)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return LogpushJob{}, err
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return LogpushJob{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}
// UpdateLogpushJob lets you update a Logpush Job.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-update-logpush-job
func (api *API) UpdateLogpushJob(ctx context.Context, rc *ResourceContainer, params UpdateLogpushJobParams) error {
uri := fmt.Sprintf("/%s/%s/logpush/jobs/%d", rc.Level, rc.Identifier, params.ID)
res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params)
if err != nil {
return err
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return nil
}
// DeleteLogpushJob deletes a Logpush Job for a zone.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-delete-logpush-job
func (api *API) DeleteLogpushJob(ctx context.Context, rc *ResourceContainer, jobID int) error {
uri := fmt.Sprintf("/%s/%s/logpush/jobs/%d", rc.Level, rc.Identifier, jobID)
res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
if err != nil {
return err
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return nil
}
// GetLogpushOwnershipChallenge returns ownership challenge.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-get-ownership-challenge
func (api *API) GetLogpushOwnershipChallenge(ctx context.Context, rc *ResourceContainer, params GetLogpushOwnershipChallengeParams) (*LogpushGetOwnershipChallenge, error) {
uri := fmt.Sprintf("/%s/%s/logpush/ownership", rc.Level, rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
if err != nil {
return nil, err
}
var r LogpushGetOwnershipChallengeResponse
err = json.Unmarshal(res, &r)
if err != nil {
return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
if !r.Result.Valid {
return nil, errors.New(r.Result.Message)
}
return &r.Result, nil
}
// ValidateLogpushOwnershipChallenge returns zone-level ownership challenge validation result.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-validate-ownership-challenge
func (api *API) ValidateLogpushOwnershipChallenge(ctx context.Context, rc *ResourceContainer, params ValidateLogpushOwnershipChallengeParams) (bool, error) {
uri := fmt.Sprintf("/%s/%s/logpush/ownership/validate", rc.Level, rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
if err != nil {
return false, err
}
var r LogpushGetOwnershipChallengeResponse
err = json.Unmarshal(res, &r)
if err != nil {
return false, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result.Valid, nil
}
// CheckLogpushDestinationExists returns zone-level destination exists check result.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-check-destination-exists
func (api *API) CheckLogpushDestinationExists(ctx context.Context, rc *ResourceContainer, destinationConf string) (bool, error) {
uri := fmt.Sprintf("/%s/%s/logpush/validate/destination/exists", rc.Level, rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, LogpushDestinationExistsRequest{
DestinationConf: destinationConf,
})
if err != nil {
return false, err
}
var r LogpushDestinationExistsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return false, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result.Exists, nil
}