seed

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2022 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultNewResourceFuncs = map[model.Type]NewResourceFunc{
	resource.TypeCACertificate: func(_ Seeder, m proto.Message, _ int) error {
		r := m.(*v1.CACertificate)
		var err error
		r.Cert, _, err = util.GenerateCertificate(defaultCertificateBits)
		return err
	},
	resource.TypeCertificate: func(_ Seeder, m proto.Message, _ int) error {
		r := m.(*v1.Certificate)
		var err error
		r.Cert, r.Key, err = util.GenerateCertificate(defaultCertificateBits)
		return err
	},
	resource.TypeConsumer: func(_ Seeder, m proto.Message, i int) error {
		r := m.(*v1.Consumer)
		r.Username = fmt.Sprintf("username-%d", i+1)
		return nil
	},
	resource.TypePlugin: func(s Seeder, m proto.Message, i int) error {
		r := m.(*v1.Plugin)
		r.Name = "key-auth"
		services := s.Results().ByType(resource.TypeService).All()
		if l := len(services); l == 0 {
			return errors.New("must create services before seeding plugins, in order to ensure unique resources")
		} else if l < i+1 {
			return errors.New("must create an equal number of services & plugins")
		}
		r.Service = &v1.Service{Id: services[i].ID}
		return nil
	},
	resource.TypePluginSchema: func(s Seeder, m proto.Message, i int) error {
		r := m.(*v1.PluginSchema)
		r.LuaSchema = fmt.Sprintf(`return {
			name = "%s",
			fields = {
				{ config = {
						type = "record",
						fields = {
							{ field = { type = "string" } }
						}
					}
				}
			}
		}`, fmt.Sprintf("plugin-schema-%d", i+1))
		return nil
	},
	resource.TypeRoute: func(_ Seeder, m proto.Message, i int) error {
		r := m.(*v1.Route)
		r.Name, r.Hosts = fmt.Sprintf("route-%d", i+1), []string{"example.com"}
		return nil
	},
	resource.TypeService: func(_ Seeder, m proto.Message, i int) error {
		r := m.(*v1.Service)
		r.Name, r.Host = fmt.Sprintf("service-%d", i+1), "example.com"
		return nil
	},
	resource.TypeSNI: func(s Seeder, m proto.Message, i int) error {
		r := m.(*v1.SNI)
		r.Name = fmt.Sprintf("example-%d.com", i)
		certificates := s.Results().ByType(resource.TypeCertificate).All()
		if len(certificates) == 0 {
			return errors.New("must create at least one certificate before seeding SNIs")
		}
		r.Certificate = &v1.Certificate{Id: certificates[0].ID}
		return nil
	},
	resource.TypeTarget: func(s Seeder, m proto.Message, i int) error {
		r := m.(*v1.Target)
		r.Target = "127.0.0.1:8080"
		upstreams := s.Results().ByType(resource.TypeUpstream).All()
		if l := len(upstreams); l == 0 {
			return errors.New("must create upstreams before seeding targets, in order to ensure unique resources")
		} else if l < i+1 {
			return errors.New("must create an equal number of upstreams & targets")
		}
		r.Upstream = &v1.Upstream{Id: upstreams[i].ID}
		return nil
	},
	resource.TypeUpstream: func(_ Seeder, m proto.Message, i int) error {
		r := m.(*v1.Upstream)
		r.Name = fmt.Sprintf("upstream-%d", i+1)
		return nil
	},
}

DefaultNewResourceFuncs contains the NewResourceFunc functions for resources that require other fields to be set. Read the documentation on the NewResourceFunc for more info.

This map must not be updated after application initialization (as it is not safe to update while a seeder is running). It is exported to allow callers the ability to define new functions that piggyback off the default behavior.

We know the resources are of the proper type, so we're disabling the type assertion linter.

View Source
var DefaultRandSourceFunc = func(typ model.Type) (rand.Source, error) {

	h := fnv.New32a()
	if _, err := h.Write([]byte(typ)); err != nil {
		return nil, err
	}
	return rand.NewSource(int64(h.Sum32())), nil
}

DefaultRandSourceFunc defines the default function used for determining the random source based on a given type.

View Source
var ErrRequiredFieldMissing = errors.New("field does not exist for type")

ErrRequiredFieldMissing is returned during a seed call when a type does not have a required field to properly seed the resource. For example, this can happen when tags should be created, however, the resource is missing the `tags` field.

Functions

This section is empty.

Types

type ModifyHTTPRequestFunc

type ModifyHTTPRequestFunc func(model.Type, *http.Request) error

ModifyHTTPRequestFunc defines a function that can manipulate the passed in HTTP request for the given type. The function must be safe for concurrent use.

type NewResourceFunc

type NewResourceFunc func(Seeder, proto.Message, int) error

NewResourceFunc allows the seeder to properly set the desired fields on a resource that require more fields than just an ID to be created.

The passed in seeder can be used to get IDs of dependent resources.

The passed in integer is the current resource's index in the underling storage. This is helpful when the resource requires a dependency, and uniqueness needs to be ensured.

The function must be safe for concurrent use.

type NewSeederOpts

type NewSeederOpts struct {
	// The URL to the control plane RESTful API, with the scheme. e.g.: http://127.0.0.1:8080
	URL string

	// Optional max amount of resources to be seeded at one time. When zero,
	// defaults to runtime.NumCPU(). Otherwise, must be a positive number.
	ConcurrencyLimit int

	// Optional HTTP client to use. When nil, will default to http.DefaultClient.
	HTTPClient *http.Client

	// Optional function that handles setting the random source used for deterministically generating random
	// data, like tags, based on the given type name. When nil, defaults to DefaultRandSourceFunc.
	RandSourceFunc func(typ model.Type) (rand.Source, error)

	// Optional map allowing to set custom NewResourceFunc functions, that will be called for the associated
	// type when creating the resource. When empty, will default to DefaultNewResourceFuncs.
	NewResourceFuncs map[model.Type]NewResourceFunc

	// Optional Protobuf registry, used for HTTP rule binding verification.
	// When nil, defaults to protoregistry.GlobalFiles.
	ProtoRegistry *protoregistry.Files
}

NewSeederOpts defines the configuration used to instantiate a new seeder. The config should not be updated after it is set on a seeder.

type Options

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

Options defines the non-exported options that the Seeder seed methods can take in. Must be formed using NewOptionsBuilder().

type OptionsBuilder

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

OptionsBuilder allows seeder options to be built, used for each seed call.

func NewOptionsBuilder

func NewOptionsBuilder() *OptionsBuilder

NewOptionsBuilder instantiates a new instance of an OptionsBuilder.

func (*OptionsBuilder) Build

func (b *OptionsBuilder) Build() (*Options, error)

Build validates the passed in options & returns the generated options, that can be passed to the seed methods.

func (*OptionsBuilder) WithIgnoredErrors

func (b *OptionsBuilder) WithIgnoredErrors(errs ...error) *OptionsBuilder

WithIgnoredErrors can be used to skip specific errors when seeding all types with the Seeder.SeedAllTypes() call. For example,the ErrRequiredFieldMissing error can be set to continue seeding when a type is missing a field that is expected.

func (*OptionsBuilder) WithIncrementalTags

func (b *OptionsBuilder) WithIncrementalTags(count int) *OptionsBuilder

WithIncrementalTags sets the specified number of unique tags on each resource, starting from "tag-1".

The count argument must be a non-zero, positive number, and it represents the max number of tags that can be created on a resource. If it's set to one, each resource will only have one tag. If it's set to any higher number, resources can have more than one tag, but each tag is only used once.

E.g.: If ten resources are being seeded, with the count set to one, "tag-1"-"tag-10" will be used. In the event the seeder is run multiple times, it will still ensure unique tags (as long as this option is specified).

func (*OptionsBuilder) WithModifyHTTPRequestFuncs

func (b *OptionsBuilder) WithModifyHTTPRequestFuncs(modifyRequestFuncs ...ModifyHTTPRequestFunc) *OptionsBuilder

WithModifyHTTPRequestFuncs can be used to modify the HTTP request to create a resource. The functions are executed in the order they are provided.

func (*OptionsBuilder) WithNewResourceFunc

func (b *OptionsBuilder) WithNewResourceFunc(typ model.Type, inheritDefault bool, f NewResourceFunc) *OptionsBuilder

WithNewResourceFunc overrides a default NewResourceFunc for a single seed call.

When inheritDefault is true, the new resource function on the seeder will be executed before, and if said function is not defined, it will then default to those defined in DefaultNewResourceFuncs.

func (*OptionsBuilder) WithRandomTagCount

func (b *OptionsBuilder) WithRandomTagCount(count int, allowEmpty bool) *OptionsBuilder

WithRandomTagCount sets the max number of tags to be created, starting from "tag-1".

When zero (or option is redacted), no tags will be set on the resources. When the field is non-zero, random tags will be created for each object (using NewSeederOpts.RandSourceFunc), up to the given amount.

The allowEmpty flag controls whether resources can be created with no tags.

E.g.: If `2` is set & allowEmpty is true, a resource can have any of the given combinations of tags: (no tags), `tag-1`, `tag-2`, `tag-1, tag-2`.

func (*OptionsBuilder) WithResourceCount

func (b *OptionsBuilder) WithResourceCount(count int) *OptionsBuilder

WithResourceCount sets the number of resources to create for each type being seeded. Must be a non-zero, positive number.

func (*OptionsBuilder) WithStaticTags

func (b *OptionsBuilder) WithStaticTags(tags []string) *OptionsBuilder

WithStaticTags sets optional tags to set on each resource. When used, this overrides all default tag generation behavior (as in, no other tags will be set but these).

type ResourceInfo

type ResourceInfo struct {
	// The resource being described.
	Name model.Type

	// Our custom JSON schema extension defining internal config for a resource.
	JSONSchemaConfig *extension.Config

	// The relevant JSON schema for this resource.
	Schema *jsonschema.Schema
	// contains filtered or unexported fields
}

ResourceInfo stores various information related to a specific resource.

func (*ResourceInfo) HasField

func (ri *ResourceInfo) HasField(fieldName string) bool

HasField is a helper function to determine if a field exists on the JSON schema.

type Result

type Result struct {
	ID       string
	Tags     []string
	Resource proto.Message
}

Result defines a single resource, with some common fields shared across resources & its underling Protobuf message.

func (*Result) ToMap

func (r *Result) ToMap() (map[string]interface{}, error)

ToMap returns a JSON-based representation of the resource. This is safe for concurrent use.

type Results

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

Results is a list of Result objects.

func (*Results) Add

func (r *Results) Add(typ model.Type, results *Results)

Add is used to insert new results for a specific type. This is safe for concurrent use.

func (*Results) All

func (r *Results) All() []*Result

All returns all results, regardless of resource type. This is safe for concurrent use.

func (*Results) AllByType

func (r *Results) AllByType() map[model.Type]*Results

AllByType returns all results keyed by its resource type. This is safe for concurrent use.

func (*Results) ByType

func (r *Results) ByType(typ model.Type) *Results

ByType returns the given results for a particular resource type. In the event no results were created for the type, nil is returned. This is safe for concurrent use.

func (*Results) GetByID

func (r *Results) GetByID(id string) *Result

GetByID attempts to find the given result by its ID. Returns nil when not found. This is safe for concurrent use.

func (*Results) IDs

func (r *Results) IDs() []string

IDs returns a sorted list of all resource IDs on the given results object. This is safe for concurrent use.

type Seeder

type Seeder interface {
	// Results returns all resources that were created by result of running the seeder (in the event
	// the seeder was run multiple times, all resources created across each run will be returned).
	Results() *Results

	// AllResourceInfo returns extended information about all registered resources that are capable of being seeded.
	//
	// Resources that cannot be seeded include:
	// - Resources missing `$["x-koko-config"].resourceAPIPath` on the JSON schema.
	// - Resources missing a `POST /v1/(resource)` HTTP binding defined on the gRPC service.
	AllResourceInfo() []*ResourceInfo

	// ResourceInfoByType returns extended information for the provided resource.
	ResourceInfoByType(typ model.Type) *ResourceInfo

	// SeedAllTypes creates resources, based on the provided options, for all registered
	// resources. For more information, read the documentation for Seeder.Seed().
	SeedAllTypes(context.Context, *Options) (*Results, error)

	// Seed creates the given number of resources for the provided resource. The newly created results will be
	// returned & added to the underlining seeder object.
	//
	// In the event this method is called multiple times, any newly created resources will be appended to the
	// seeder instance. This will affect the results when calling seeder.Results().
	//
	// The ErrNoResourcePath & ErrRequiredFieldMissing errors may be returned as a wrapped error, and can be
	// checked using errors.Is(). See documentation for the mentioned errors in this file for more detail.
	Seed(context.Context, *Options, ...model.Type) (*Results, error)
}

Seeder handles creating test resources, usually used to ease integration testing. All methods defined on the interface are safe for concurrent use.

func New

func New(opts NewSeederOpts) (Seeder, error)

New instantiates a seeder with the given config.

In the event new resources are registered, you must instantiate a new seeder for those resources to be picked up.

Jump to

Keyboard shortcuts

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