ddmark

package
v0.0.0-...-9d1fdd8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 12, 2024 License: Apache-2.0 Imports: 13 Imported by: 0

README

DDMARK

What is it ?

DDMark is a validation module embedded in the chaos-controller, used to apply validation rules to the Kubernetes Custom Resource Definition of the chaos-controller, Disruptions. It allows for defining rules that put constraints on fields, which will be applied when they're unmarshalled from a file, or read.

Why does it exist ?

DDMark emerged as an idea when using kubebuilder, which uses markers to put constraints on CRD (Custom Resource Definition) fields. Those constraints could later only be applied when parsed by the kubernetes api, which isn't very practical for other uses. It was decided to use the same markers in a customized way to be more flexible and usable.

DDMarkers can be validated through code, which allows us to validate through a CLI and any valid go runner - no need for kubernetes anymore. It also allows us to define custom rules to apply to our structures, and focus the code validation within the chaos-controller to environment-specific validation (does this service exist in this cluster ? Is my cluster in a supported version ?) and not structural config validation (is this field under 100 like we need it to be ?), which would end up being very annoying, cluttered and messy code.

How to use DDMark ?

  1. Setup ddmark fields in your library:
  • Define new rules/read the existing rules within the ddmark/validation/validation.go file (or in this doc)
  • Examples can be found in the ddmark/teststruct.go file
  • Add the desired rules to the appropriate struct fields in the package you wish to add validation to (care for type checking - e.g. Maximum rule can only be applied to int/uint fields). Correct format is // +ddmark:validation:<rulename>=<value>
  • The analyzed library has to contain a self-packaging exported Embed.FS field. This field will then be used by ddmark to import the versioned files into any executable.
  1. Call the validation function from your code:
  • Requirement: code needs to run on a go 1.18+ environment
  • DDMark works through a client interface (which is linked to internal disk resources). Each client instance created with ddmark.NewClient(<embed.FS>) works independently and can be used concurrently. Use client.CleanupLibraries() to remove all files related to a specific client, or ddmark.CleanupAllLibraries() to clean up all the clients' files.
  • Call the ValidateStruct() function with the unmarshalled struct, and the current file/location for debugging purposes (this is a validation tool !). Check cli/chaosli/cmd/validate.go for a functioning example.

Markers Documentation

Field Markers (within structs)
  • Enum:
    • // +ddmark:validation:Enum={<any>,<any>,...}
    • Applies to: <any> field
    • Asserts field value is one of the given values of the Enum list
  • Maximum:
    • // +ddmark:validation:Maximum=<int/uint>
    • Applies to: int/uint field
    • Asserts a value is equal or inferior to a given int
  • Minimum:
    • // +ddmark:validation:Minimum=<int/uint>
    • Applies to: int/uint field
    • Asserts a value is equal or superior to the given int
  • Required:
    • // +ddmark:validation:Required=<bool>
    • Applies to: <any> field
    • Asserts the concerned field isn’t nil (or 0, “”, or other null value)
Type Markers (outside structs)
  • ExclusiveFields:
    • // +ddmark:validation:ExclusiveFields={<fieldName1>,<fieldName2>,...}
    • Applies to: any <struct> type
    • Asserts that <fieldname1> can only be non-nil iff all of the other fields are nil
  • LinkedFieldsValue:
    • without values:
      • // +ddmark:validation:LinkedFieldsValue={<fieldName1>,<fieldName2>,...}
      • Applies to: any <struct> type
      • Asserts the fields in the list are either all nil or all non-nil
    • with values:
      • // +ddmark:validation:LinkedFieldsValue={<fieldName1>=<value>,<fieldName2>,...}
      • Applies to: any <struct> type -- value checks are only for string and int subfields
      • Asserts the fields in the list are either all nil (or are specifically set to the indicated value) or all non-nil (or are specifically not set to the given value)
      • Fields with values and without values can be mixed
  • LinkedFieldsValueWithTrigger
    • without values:
      • // +ddmark:validation:LinkedFieldsValueWithTrigger={<fieldName1>, <fieldName2>,...}
      • Applies to: any <struct> type
      • Asserts the following: if the first field is non-nil, all the following fields have to also be non-nil
    • with values:
      • // +ddmark:validation:LinkedFieldsValueWithTrigger={<fieldName1>=<value>, <fieldName2>,...}
      • Applies to: any <struct> type -- value checks are only for string and int subfields
      • Asserts the following: if the first field is non-nil OR is set to the given <value>, all the following fields have to also be non-nil OR set to their given <value>.
      • Fields with values and without values can be mixed
  • AtLeastOneOf:
    • // +ddmark:validation:AtLeastOneOf={<fieldName1>,<fieldName2>,...}
    • Applies to: any <struct> type
    • Asserts at least one of the fields in the list is non-nil.
      • Note: if all the sub-fields of the <struct> can be/are nil, the parent field will be nil and this marker will be ignored. In this case, please consider using the Required marker on the parent field.

Documentation

Overview

Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2024 Datadog, Inc.

Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2024 Datadog, Inc.

This struct cannot be within the ddmark_test package in order to be properly loaded by the loader package, inherent to the markers

Index

Constants

This section is empty.

Variables

View Source
var (
	AllDefinitions []*k8smarkers.Definition
)

AllDefinitions contains all marker definitions for this package.

View Source
var EmbeddedDDMarkAPI embed.FS

EmbeddedDDMarkAPI includes the teststruct so it can be statically exported for ddmark testing

Functions

func CleanupAllLibraries

func CleanupAllLibraries() error

CleanupAllLibraries deletes the common ddmark lib folder ($GOPATH/src/ddmarktemp/*) Will remove the disk dependencies for all ddmark clients.

func GetErrorList

func GetErrorList(errorList []error) string

GetErrorList returns a list of errors as a string

func Register

func Register(reg *k8smarkers.Registry) error

Types

type AtLeastOneOf

type AtLeastOneOf []string

AtLeastOneOf can be applied to structs, and asserts at least one of the following fields is non-'nil'

func (AtLeastOneOf) ApplyRule

func (a AtLeastOneOf) ApplyRule(fieldvalue reflect.Value) error

func (AtLeastOneOf) TypeCheckError

func (a AtLeastOneOf) TypeCheckError(fieldValue reflect.Value) error

func (AtLeastOneOf) ValueCheckError

func (a AtLeastOneOf) ValueCheckError() error

type AtLeastOneOfTestStruct

type AtLeastOneOfTestStruct struct {
	RandomIntField int // allows to actually check all-empty structs
	StrField       string
	PStrField      *string
	IntField       int
	PIntField      *int
	AIntField      []int
}

+ddmark:validation:AtLeastOneOf={StrField,IntField} +ddmark:validation:AtLeastOneOf={PStrField,PIntField,AIntField}

type Client

type Client interface {
	// ValidateStruct applies struct markers found in structPkgs struct definitions to a marshalledStruct object.
	// It allows to enforce ddmark rules onto that object, according to the constraints defined in struct file.
	ValidateStruct(marshalledStruct interface{}, filePath string) []error
	// ValidateStructMultierror is the parent function of ValidateStruct.
	// It allows users to leverage the multierror package for error management.
	ValidateStructMultierror(marshalledStruct interface{}, filePath string) (retErr *multierror.Error)
	// CleanupLibraries removes the disk files related to the client.
	CleanupLibraries() error
}

Client interface to manage validation of struct fields

Client is the expected way to use DDMark. Create a client with ddmark.NewClient(embed.FS). The client interfaces with local-disk copies of the given files. DDMark clients can be used simultaneously, as they manage independent/separate disk resources.

Client creates local files in the GOPATH. Make sure to use Client.CleanupLibraries (or ddmark.CleanupAllLibraries) to remove them.

func NewClient

func NewClient(embeddedFS ...embed.FS) (Client, error)

NewClient create an new instance of DDMark

type ClientMock

type ClientMock struct {
	mock.Mock
}

ClientMock is an autogenerated mock type for the Client type

func NewClientMock

func NewClientMock(t interface {
	mock.TestingT
	Cleanup(func())
}) *ClientMock

NewClientMock creates a new instance of ClientMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. The first argument is typically a *testing.T value.

func (*ClientMock) CleanupLibraries

func (_m *ClientMock) CleanupLibraries() error

CleanupLibraries provides a mock function with given fields:

func (*ClientMock) EXPECT

func (_m *ClientMock) EXPECT() *ClientMock_Expecter

func (*ClientMock) ValidateStruct

func (_m *ClientMock) ValidateStruct(marshalledStruct interface{}, filePath string) []error

ValidateStruct provides a mock function with given fields: marshalledStruct, filePath

func (*ClientMock) ValidateStructMultierror

func (_m *ClientMock) ValidateStructMultierror(marshalledStruct interface{}, filePath string) *multierror.Error

ValidateStructMultierror provides a mock function with given fields: marshalledStruct, filePath

type ClientMock_CleanupLibraries_Call

type ClientMock_CleanupLibraries_Call struct {
	*mock.Call
}

ClientMock_CleanupLibraries_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CleanupLibraries'

func (*ClientMock_CleanupLibraries_Call) Return

func (*ClientMock_CleanupLibraries_Call) Run

func (*ClientMock_CleanupLibraries_Call) RunAndReturn

type ClientMock_Expecter

type ClientMock_Expecter struct {
	// contains filtered or unexported fields
}

func (*ClientMock_Expecter) CleanupLibraries

func (_e *ClientMock_Expecter) CleanupLibraries() *ClientMock_CleanupLibraries_Call

CleanupLibraries is a helper method to define mock.On call

func (*ClientMock_Expecter) ValidateStruct

func (_e *ClientMock_Expecter) ValidateStruct(marshalledStruct interface{}, filePath interface{}) *ClientMock_ValidateStruct_Call

ValidateStruct is a helper method to define mock.On call

  • marshalledStruct interface{}
  • filePath string

func (*ClientMock_Expecter) ValidateStructMultierror

func (_e *ClientMock_Expecter) ValidateStructMultierror(marshalledStruct interface{}, filePath interface{}) *ClientMock_ValidateStructMultierror_Call

ValidateStructMultierror is a helper method to define mock.On call

  • marshalledStruct interface{}
  • filePath string

type ClientMock_ValidateStructMultierror_Call

type ClientMock_ValidateStructMultierror_Call struct {
	*mock.Call
}

ClientMock_ValidateStructMultierror_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValidateStructMultierror'

func (*ClientMock_ValidateStructMultierror_Call) Return

func (*ClientMock_ValidateStructMultierror_Call) Run

func (_c *ClientMock_ValidateStructMultierror_Call) Run(run func(marshalledStruct interface{}, filePath string)) *ClientMock_ValidateStructMultierror_Call

func (*ClientMock_ValidateStructMultierror_Call) RunAndReturn

type ClientMock_ValidateStruct_Call

type ClientMock_ValidateStruct_Call struct {
	*mock.Call
}

ClientMock_ValidateStruct_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValidateStruct'

func (*ClientMock_ValidateStruct_Call) Return

func (*ClientMock_ValidateStruct_Call) Run

func (_c *ClientMock_ValidateStruct_Call) Run(run func(marshalledStruct interface{}, filePath string)) *ClientMock_ValidateStruct_Call

func (*ClientMock_ValidateStruct_Call) RunAndReturn

func (_c *ClientMock_ValidateStruct_Call) RunAndReturn(run func(interface{}, string) []error) *ClientMock_ValidateStruct_Call

type DDValidationMarker

type DDValidationMarker interface {
	// ApplyRule asserts the marker's rule is checked and returns an error if it isn't (invalidating the config)
	ApplyRule(reflect.Value) error
	// ValueCheckError returns a marker's error message for an incorrect value/presence check
	ValueCheckError() error
	// TypeCheckError returns a marker's error message for an incorrect type check
	TypeCheckError(reflect.Value) error
}

DDValidationMarker is the interface for Validation Markers, which apply rules to a given structure's field

type DDValidationMarkerMock

type DDValidationMarkerMock struct {
	mock.Mock
}

DDValidationMarkerMock is an autogenerated mock type for the DDValidationMarker type

func NewDDValidationMarkerMock

func NewDDValidationMarkerMock(t interface {
	mock.TestingT
	Cleanup(func())
}) *DDValidationMarkerMock

NewDDValidationMarkerMock creates a new instance of DDValidationMarkerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. The first argument is typically a *testing.T value.

func (*DDValidationMarkerMock) ApplyRule

func (_m *DDValidationMarkerMock) ApplyRule(_a0 reflect.Value) error

ApplyRule provides a mock function with given fields: _a0

func (*DDValidationMarkerMock) EXPECT

func (*DDValidationMarkerMock) TypeCheckError

func (_m *DDValidationMarkerMock) TypeCheckError(_a0 reflect.Value) error

TypeCheckError provides a mock function with given fields: _a0

func (*DDValidationMarkerMock) ValueCheckError

func (_m *DDValidationMarkerMock) ValueCheckError() error

ValueCheckError provides a mock function with given fields:

type DDValidationMarkerMock_ApplyRule_Call

type DDValidationMarkerMock_ApplyRule_Call struct {
	*mock.Call
}

DDValidationMarkerMock_ApplyRule_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyRule'

func (*DDValidationMarkerMock_ApplyRule_Call) Return

func (*DDValidationMarkerMock_ApplyRule_Call) Run

func (*DDValidationMarkerMock_ApplyRule_Call) RunAndReturn

type DDValidationMarkerMock_Expecter

type DDValidationMarkerMock_Expecter struct {
	// contains filtered or unexported fields
}

func (*DDValidationMarkerMock_Expecter) ApplyRule

ApplyRule is a helper method to define mock.On call

  • _a0 reflect.Value

func (*DDValidationMarkerMock_Expecter) TypeCheckError

TypeCheckError is a helper method to define mock.On call

  • _a0 reflect.Value

func (*DDValidationMarkerMock_Expecter) ValueCheckError

ValueCheckError is a helper method to define mock.On call

type DDValidationMarkerMock_TypeCheckError_Call

type DDValidationMarkerMock_TypeCheckError_Call struct {
	*mock.Call
}

DDValidationMarkerMock_TypeCheckError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TypeCheckError'

func (*DDValidationMarkerMock_TypeCheckError_Call) Return

func (*DDValidationMarkerMock_TypeCheckError_Call) Run

func (*DDValidationMarkerMock_TypeCheckError_Call) RunAndReturn

type DDValidationMarkerMock_ValueCheckError_Call

type DDValidationMarkerMock_ValueCheckError_Call struct {
	*mock.Call
}

DDValidationMarkerMock_ValueCheckError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValueCheckError'

func (*DDValidationMarkerMock_ValueCheckError_Call) Return

func (*DDValidationMarkerMock_ValueCheckError_Call) Run

func (*DDValidationMarkerMock_ValueCheckError_Call) RunAndReturn

type Enum

type Enum []interface{}

Enum can be applied to any interface field and provides a restricted amount of possible values for that field. Values within the marker strictly need to fit the given field interface. Usage is recommended to simple types.

func (Enum) ApplyRule

func (e Enum) ApplyRule(fieldvalue reflect.Value) error

func (Enum) TypeCheckError

func (e Enum) TypeCheckError(fieldValue reflect.Value) error

func (Enum) ValueCheckError

func (e Enum) ValueCheckError() error

type EnumTestStruct

type EnumTestStruct struct {
	// +ddmark:validation:Enum={aa,bb,11}
	StrField string
	// +ddmark:validation:Enum={aa,bb,11}
	PStrField *string
	// +ddmark:validation:Enum={1,2,3}
	IntField int
	// +ddmark:validation:Enum={1,2,3}
	PIntField *int
}

type ExclusiveFields

type ExclusiveFields []string

ExclusiveFields can be applied to structs, and asserts that the first field can only be non-'nil' iff all of the other fields are 'nil'

func (ExclusiveFields) ApplyRule

func (e ExclusiveFields) ApplyRule(fieldvalue reflect.Value) error

func (ExclusiveFields) TypeCheckError

func (e ExclusiveFields) TypeCheckError(fieldValue reflect.Value) error

func (ExclusiveFields) ValueCheckError

func (e ExclusiveFields) ValueCheckError() error

type ExclusiveFieldsTestStruct

type ExclusiveFieldsTestStruct struct {
	IntField  int
	PIntField *int
	StrField  string
	PStrField *string
	BField    int
	CField    int
}

+ddmark:validation:ExclusiveFields={PIntField,PStrField} +ddmark:validation:ExclusiveFields={PIntField,BField,CField} +ddmark:validation:ExclusiveFields={IntField,StrField}

type LinkedFieldsValue

type LinkedFieldsValue []string

LinkedFieldsValue can be applied to structs, and asserts the fields in the list are either all 'nil' or all non-'nil'

func (LinkedFieldsValue) ApplyRule

func (l LinkedFieldsValue) ApplyRule(fieldvalue reflect.Value) error

func (LinkedFieldsValue) TypeCheckError

func (l LinkedFieldsValue) TypeCheckError(fieldValue reflect.Value) error

func (LinkedFieldsValue) ValueCheckError

func (l LinkedFieldsValue) ValueCheckError() error

type LinkedFieldsValueTestStruct

type LinkedFieldsValueTestStruct struct {
	RandomIntField int // allows to actually check all-empty structs
	StrField       string
	PStrField      *string
	IntField       int
	PIntField      *int
	AIntField      []int
}

+ddmark:validation:LinkedFieldsValue={StrField=aaa,IntField} +ddmark:validation:LinkedFieldsValue={PStrField,PIntField,AIntField}

type LinkedFieldsValueWithTrigger

type LinkedFieldsValueWithTrigger []string

LinkedFieldsValueWithTrigger can be applied to structs, and asserts the following: - if first field exists (or has the indicated value), all the following fields need to exist (or have the indicated value) - fields in question can be int or strings

func (LinkedFieldsValueWithTrigger) ApplyRule

func (l LinkedFieldsValueWithTrigger) ApplyRule(fieldvalue reflect.Value) error

func (LinkedFieldsValueWithTrigger) TypeCheckError

func (l LinkedFieldsValueWithTrigger) TypeCheckError(fieldValue reflect.Value) error

func (LinkedFieldsValueWithTrigger) ValueCheckError

func (l LinkedFieldsValueWithTrigger) ValueCheckError() error

type LinkedFieldsValueWithTriggerTestStruct

type LinkedFieldsValueWithTriggerTestStruct struct {
	RandomIntField int // allows to actually check all-empty structs
	StrField       string
	PStrField      *string
	IntField       int
	PIntField      *int
	AIntField      []int
}

+ddmark:validation:LinkedFieldsValueWithTrigger={StrField=aaa,IntField=2} +ddmark:validation:LinkedFieldsValueWithTrigger={PStrField=bbb,PIntField=12,AIntField}

type Maximum

type Maximum int

Maximum can applied to an int field and provides a (non-strict) maximum value for that field

func (Maximum) ApplyRule

func (m Maximum) ApplyRule(fieldvalue reflect.Value) error

func (Maximum) TypeCheckError

func (m Maximum) TypeCheckError(fieldValue reflect.Value) error

func (Maximum) ValueCheckError

func (m Maximum) ValueCheckError() error

type MinMaxTestStruct

type MinMaxTestStruct struct {
	// +ddmark:validation:Minimum=5
	// +ddmark:validation:Maximum=10
	IntField int
	// +ddmark:validation:Minimum=5
	// +ddmark:validation:Maximum=10
	PIntField *int
}

type Minimum

type Minimum int

Minimum can applied to an int field and provides a (non-strict) minimum value for that field

func (Minimum) ApplyRule

func (m Minimum) ApplyRule(fieldvalue reflect.Value) error

func (Minimum) TypeCheckError

func (m Minimum) TypeCheckError(fieldValue reflect.Value) error

func (Minimum) ValueCheckError

func (m Minimum) ValueCheckError() error

type Required

type Required bool

Required can be applied to any field, and asserts this field will return an error if not provided

func (Required) ApplyRule

func (r Required) ApplyRule(fieldvalue reflect.Value) error

func (Required) TypeCheckError

func (r Required) TypeCheckError(fieldValue reflect.Value) error

func (Required) ValueCheckError

func (r Required) ValueCheckError() error

type RequiredTestStruct

type RequiredTestStruct struct {
	// +ddmark:validation:Required=true
	IntField int
	// +ddmark:validation:Required=true
	PIntField *int
	// +ddmark:validation:Required=true
	StrField string
	// +ddmark:validation:Required=true
	PStrField *string
	// +ddmark:validation:Required=true
	StructField struct {
		A int
	}
	// +ddmark:validation:Required=true
	PStructField *struct {
		A int
	}
}

type Teststruct

type Teststruct struct {
	MinMaxTest                       MinMaxTestStruct
	RequiredTest                     RequiredTestStruct
	EnumTest                         EnumTestStruct
	ExclusiveFieldsTest              ExclusiveFieldsTestStruct
	LinkedFieldsValueTest            LinkedFieldsValueTestStruct
	LinkedFieldsValueWithTriggerTest LinkedFieldsValueWithTriggerTestStruct
	AtLeastOneOfTest                 AtLeastOneOfTestStruct
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL