Skip to content

Return errors on the Send and batchSend operations #914

@aerosouund

Description

@aerosouund

Currently, the signature for the client interface specifies that the methods for sending return no errors, when in fact errors do occur in them.
It would be better to return the errors obtained from those methods and ignore the error or log it at a higher level in the code. e.g: send-result.go, scope_result.go.

This allows for a higher degree of decoupling between the targets package and the listeners package and opens the opportunity for the targets package to be used across many systems in the future.

Here's an example of how might this look:

pkg/target/client.go:

type Client interface {
	// Send the given Result to the configured Target
	Send(result payload.Payload) error
	// BatchSend the given Results of a single PolicyReport to the configured Target
	BatchSend(report v1alpha2.ReportInterface, results []payload.Payload) []error
	// other methods
}

pkg/target/s3/s3.go

func (c *client) Send(result payload.Payload) error {
	if len(c.customFields) > 0 {
		if err := result.AddCustomFields(c.customFields); err != nil {
			return err
		}
	}
	resultBody := result.Body()
	body := new(bytes.Buffer)

	if err := json.NewEncoder(body).Encode(resultBody); err != nil {
		return err
	}

	key := result.BlobStorageKey(c.prefix)
	if err := c.s3.Upload(body, key); err != nil {
		return err
	}

	zap.L().Info(c.Name() + ": PUSH OK")
	return nil
}

pkg/listener/send_result.go

func NewSendResultListener(targets *target.Collection) report.PolicyReportResultListener {
	return func(rep v1alpha2.ReportInterface, r v1alpha2.PolicyReportResult, e bool) {
		clients := targets.SingleSendClients()
		if len(clients) == 0 {
			return
		}

		wg := &sync.WaitGroup{}
		wg.Add(len(clients))

		for _, t := range clients {
			go func(target target.Client, re v1alpha2.ReportInterface, result v1alpha2.PolicyReportResult, preExisted bool) {
				defer wg.Done()

				if !result.HasResource() && re.GetScope() != nil {
					result.Resources = []corev1.ObjectReference{*re.GetScope()}
				}

				if (preExisted && target.SkipExistingOnStartup()) || !target.Validate(re, result) {
					return
				}
                                 
                                 // define the returned error
				err := target.Send(&payload.PolicyReportResultPayload{Result: result})
                                 // log the error with zap: zap.L().Error(c.Name()+": Error adding custom fields", zap.Error(err))

                                // return the error

                                // ignore the error

                                // put the error in a channel
			}(t, rep, r, e)
		}

		wg.Wait()
	}
}

cc: @JimBugwadia @fjogeleit

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions