resource

package
v0.16.0 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	AdmissionActionCreate  = AdmissionAction("CREATE")
	AdmissionActionUpdate  = AdmissionAction("UPDATE")
	AdmissionActionDelete  = AdmissionAction("DELETE")
	AdmissionActionConnect = AdmissionAction("CONNECT")
)
View Source
const (
	PatchOpAdd     = PatchOp("add")
	PatchOpRemove  = PatchOp("remove")
	PatchOpReplace = PatchOp("replace")
	PatchOpMove    = PatchOp("move")
	PatchOpCopy    = PatchOp("copy")
	PatchOpTest    = PatchOp("test")
)

RFC6902 PatchOp value

View Source
const (
	NamespacedScope = SchemaScope("Namespaced")
	ClusterScope    = SchemaScope("Cluster")
)
View Source
const (
	SubresourceStatus = SubresourceName("status")
	SubresourceScale  = SubresourceName("scale")
)

Subresource object names. As a "minimum supported set" in the SDK, we only present two predefined names, as only `status` and `scale` are allowed in CRDs, per https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#subresources Additional subresource names can be defined by implementers, but be aware of your storage system's restrictions.

View Source
const (
	AnnotationUpdateTimestamp = "grafana.com/updateTimestamp"
	AnnotationCreatedBy       = "grafana.com/createdBy"
	AnnotationUpdatedBy       = "grafana.com/updatedBy"
)

Annotation name constants which are used by the Typed and Untyped Objects for converting non-kubernetes metadata into CommonMetadata attributes. While it is not required for Object implementations to use these annotations for storing non-kubernetes CommonMetadata fields, it is encouraged for maximum compatibility.

View Source
const NamespaceAll = ""

Variables

This section is empty.

Functions

func WithKind

func WithKind(kind string) func(*SimpleSchema)

WithKind returns a SimpleSchemaOption that sets the SimpleSchema's Kind to the provided string TODO: still unsure on whether kind should be optional? It feels non-idiomatic to grab the kind from the reflected type name

func WithPlural

func WithPlural(plural string) func(*SimpleSchema)

WithPlural returns a SimpleSchemaOption that sets the SimpleSchema's Plural to the provided string

func WithScope

func WithScope(scope SchemaScope) func(schema *SimpleSchema)

WithScope returns a SimpleSchemaOption that sets the SimpleSchema's Scope to the provided SchemaScope

Types

type APIServerResponseError added in v0.10.0

type APIServerResponseError interface {
	error
	StatusCode() int
}

type AdmissionAction added in v0.9.11

type AdmissionAction string

type AdmissionError added in v0.9.11

type AdmissionError interface {
	error
	// StatusCode should return an HTTP status code to reject with
	StatusCode() int
	// Reason should be a machine-readable reason for the rejection
	Reason() string
}

AdmissionError is an interface which extends error to add more details for admission request rejections

type AdmissionRequest added in v0.9.11

type AdmissionRequest struct {
	// Action is the type of request being checked for admission
	Action AdmissionAction
	// Kind is the object's kind
	Kind string
	// Group is the object's group
	Group string
	// Version is the object's version
	Version string
	// UserInfo is user information about the user making the request
	UserInfo AdmissionUserInfo
	// Object is the object in the request
	Object Object
	// OldObject is the object as it currently exists in storage
	OldObject Object
}

AdmissionRequest contains information from a kubernetes Admission request and decoded object(s).

type AdmissionUserInfo added in v0.9.11

type AdmissionUserInfo struct {
	// Username is the username of the user
	Username string
	// UID is the UID of the user in the API server's system
	UID string
	// Groups is a list of all groups the user is a part of (if any)
	Groups []string
	// Extra is a map of extra information, implementation-specific
	Extra map[string]any
}

AdmissionUserInfo contains user information for an admission request

type Client

type Client interface {
	// Get retrieves a resource with the given namespace and name
	Get(ctx context.Context, identifier Identifier) (Object, error)

	// GetInto retrieves a resource with the given namespace and name, and unmarshals it into `into`
	GetInto(ctx context.Context, identifier Identifier, into Object) error

	// Create creates a new resource, returning the created resource from the storage layer
	Create(ctx context.Context, identifier Identifier, obj Object, options CreateOptions) (Object, error)

	// CreateInto creates a new resource, and unmarshals the storage response (the created object) into the `into` field
	CreateInto(ctx context.Context, identifier Identifier, obj Object, options CreateOptions, into Object) error

	// Update updates a resource
	Update(ctx context.Context, identifier Identifier, obj Object, options UpdateOptions) (Object, error)

	// UpdateInto updates a response, and marshals the updated version into the `into` field
	UpdateInto(ctx context.Context, identifier Identifier, obj Object, options UpdateOptions, into Object) error

	// Patch performs a JSON Patch on an object, using the content of the PatchRequest
	Patch(ctx context.Context, identifier Identifier, patch PatchRequest, options PatchOptions) (Object, error)

	// PatchInto performs a JSON Patch on an object, using the content of the PatchRequest,
	// marshaling the returned (full) object into `into`
	PatchInto(ctx context.Context, identifier Identifier, patch PatchRequest, options PatchOptions, into Object) error

	// Delete deletes an exiting resource
	Delete(ctx context.Context, identifier Identifier) error

	// List lists objects based on the options criteria.
	// For resources with a schema.Scope() of ClusterScope, `namespace` must be resource.NamespaceAll
	List(ctx context.Context, namespace string, options ListOptions) (ListObject, error)

	// ListInto lists objects based on the options criteria, and marshals the list response into the `into` field.
	// For resources with a schema.Scope() of ClusterScope, `namespace` must be resource.NamespaceAll.
	ListInto(ctx context.Context, namespace string, options ListOptions, into ListObject) error

	// Watch makes a watch request to the provided namespace, and returns an object which implements WatchResponse
	Watch(ctx context.Context, namespace string, options WatchOptions) (WatchResponse, error)
}

Client is any object which interfaces with schema Objects. A single client should work on a per-Schema basis, where each instance of a client operates on a specific (group, version, kind). The implementation of the Client interface may re-use the same underlying communication client to the storage system, but the exposed Client should be created with a Schema in mind. For schema-agnostic Clients, use SchemalessClient.

type ClientGenerator

type ClientGenerator interface {
	// ClientFor returns a Client for the provided Schema. This returned Client is not guaranteed to be unique,
	// and can be shared by other ClientFor calls.
	ClientFor(Kind) (Client, error)
}

ClientGenerator is used for creating clients to interface with given schemas

type Codec added in v0.15.0

type Codec interface {
	Read(in io.Reader, into Object) error
	Write(out io.Writer, obj Object) error
}

Codec is an interface which describes any object which can read and write Object implementations to/from bytes. A codec is often specific to an encoding of the bytes in the reader/writer, and may also be specific to Object implementations.

type CommonMetadata

type CommonMetadata struct {
	// UID is the unique ID of the object. This can be used to uniquely identify objects,
	// but is not guaranteed to be able to be used for lookups.
	UID string `json:"uid"`
	// ResourceVersion is a version string used to identify any and all changes to the object.
	// Any time the object changes in storage, the ResourceVersion will be changed.
	// This can be used to block updates if a change has been made to the object between when the object was
	// retrieved, and when the update was applied.
	ResourceVersion string `json:"resourceVersion"`
	// Generation is a number which is incremented every time the spec of the object changes.
	// It is distinct from ResourceVersion, as it tracks only updates to the spec, and not subresources or metadata.
	Generation int64 `json:"generation"`
	// Labels are string key/value pairs attached to the object. They can be used for filtering,
	// or as additional metadata
	Labels map[string]string `json:"labels"`
	// CreationTimestamp indicates when the resource has been created.
	CreationTimestamp time.Time `json:"creationTimestamp"`
	// DeletionTimestamp indicates that the resource is pending deletion as of the provided time if non-nil.
	// Depending on implementation, this field may always be nil, or it may be a "tombstone" indicator.
	// It may also indicate that the system is waiting on some task to finish before the object is fully removed.
	DeletionTimestamp *time.Time `json:"deletionTimestamp"`
	// Finalizers are a list of identifiers of interested parties for delete events for this resource.
	// Once a resource with finalizers has been deleted, the object should remain in the store,
	// DeletionTimestamp is set to the time of the "delete," and the resource will continue to exist
	// until the finalizers list is cleared.
	Finalizers []string `json:"finalizers"`
	// UpdateTimestamp is the timestamp of the last update to the resource
	UpdateTimestamp time.Time `json:"updateTimestamp"`
	// CreatedBy is a string which indicates the user or process which created the resource.
	// Implementations may choose what this indicator should be.
	CreatedBy string `json:"createdBy"`
	// UpdatedBy is a string which indicates the user or process which last updated the resource.
	// Implementations may choose what this indicator should be.
	UpdatedBy string `json:"updatedBy"`

	// ExtraFields stores implementation-specific metadata.
	// Not all Object implementations will respect or use all possible ExtraFields.
	ExtraFields map[string]any `json:"extraFields"`
}

CommonMetadata is the generic common metadata for a resource.Object TODO: should this be in kindsys, based on the CUE type (once kindsys changes are in effect)?

type CreateOptions

type CreateOptions struct {
}

CreateOptions are the options passed to a Client.Create call

type FullIdentifier

type FullIdentifier struct {
	Namespace string
	Name      string
	Group     string
	Version   string
	Kind      string
	Plural    string
}

FullIdentifier is a globally-unique identifier, consisting of Schema identity information (Group, Version, Kind, Plural) and within-schema identity information (Namespace, Name)

type Identifier

type Identifier struct {
	Namespace string
	Name      string
}

Identifier is a unique-within-a-schema identifier, consisting of a Namespace and Name

type JSONCodec added in v0.15.0

type JSONCodec struct{}

JSONCodec is a Codec-implementing struct that reads and writes kubernetes-formatted JSON bytes.

func NewJSONCodec added in v0.15.0

func NewJSONCodec() *JSONCodec

func (*JSONCodec) Read added in v0.15.0

func (*JSONCodec) Read(in io.Reader, out Object) error

Read is a simple wrapper for the json package unmarshal into the object. TODO: expect kubernetes-formatted bytes on input?

func (*JSONCodec) Write added in v0.15.0

func (*JSONCodec) Write(out io.Writer, in Object) error

Write marshals the provided Object into kubernetes-formatted JSON bytes.

type Kind added in v0.15.0

type Kind struct {
	Schema
	Codecs map[KindEncoding]Codec
}

Kind is a struct which encapsulates Schema information and Codecs for reading/writing Objects which are instances of the contained Schema. It implements Schema using the Schema field.

func (*Kind) Codec added in v0.15.0

func (k *Kind) Codec(encoding KindEncoding) Codec

Codec is a nil-safe way of accessing the Codecs map in the Kind. It will return nil if the map key does not exist, or the key is explicitly set to nil.

func (*Kind) Read added in v0.15.0

func (k *Kind) Read(in io.Reader, encoding KindEncoding) (Object, error)

Read is a convenience wrapper for getting the Codec for a particular KindEncoding and reading into Schema.ZeroObject()

func (*Kind) Write added in v0.15.0

func (k *Kind) Write(obj Object, out io.Writer, encoding KindEncoding) error

Write is a convenience wrapper for getting the Codec for a particular KindEncoding and calling Codec.Write

type KindCollection added in v0.15.0

type KindCollection interface {
	Kinds() []Kind
}

type KindEncoding added in v0.15.0

type KindEncoding string

KindEncoding is the wire encoding of the Kind objects.

const (
	KindEncodingJSON    KindEncoding = "application/json"
	KindEncodingYAML    KindEncoding = "application/yaml"
	KindEncodingUnknown KindEncoding = ""
)

KindEncoding constants which reflect the string used for a Content-Type header.

type ListObject

type ListObject interface {
	runtime.Object
	schema.ObjectKind
	metav1.ListInterface
	GetItems() []Object
	SetItems([]Object)
	Copy() ListObject
}

ListObject represents a list of Object-implementing objects with list metadata. This interface extends the metav1.List

type ListOptions

type ListOptions struct {
	// ResourceVersion to list at
	ResourceVersion string
	// LabelFilters are a set of label filter strings to use when listing
	LabelFilters []string
	// Limit limits the number of returned results from the List call, when >0.
	// The returned ListMetadata SHOULD include the remaining item count, and the page to use for the next call.
	Limit int
	// Continue is the page to continue from when listing. If non-empty, results will begin at the page token,
	// and return up to the Limit amount.
	Continue string
}

ListOptions are the options passed to a Client.List call

type Manager

type Manager interface {
	// RegisterSchema registers a Schema in the storage system.
	// Schemas of identical group and kind, but with differing versions should not conflict.
	// If an identical group, version, and kind is already registered in the system,
	// The implementation should either return an error, or update the schema, based on the RegisterSchemaOptions.
	RegisterSchema(context.Context, Schema, RegisterSchemaOptions) error
}

Manager is an interface allowing in-code management of Schemas.

type MapSubresourceCatalog added in v0.15.0

type MapSubresourceCatalog map[string]any

type MutatingAdmissionController added in v0.9.11

type MutatingAdmissionController interface {
	// Mutate consumes an AdmissionRequest, then returns a MutatingResponse with the relevant patch operations
	// to apply. If the request should not be admitted, ths function should return an error.
	// The returned error SHOULD satisfy the AdmissionError interface, but callers will fallback
	// to using only the information in a simple error if not.
	Mutate(ctx context.Context, request *AdmissionRequest) (*MutatingResponse, error)
}

MutatingAdmissionController is an interface that describes any object which should mutate a request to manipulate a resource.Object.

type MutatingResponse added in v0.9.11

type MutatingResponse struct {
	// UpdatedObject is an updated version of the object which was passed to the MutatingAdmissionController.
	UpdatedObject Object
}

MutatingResponse is the mutation to perform on a request

type Object

type Object interface {
	runtime.Object
	schema.ObjectKind
	metav1.Object

	// GetSpec returns the Spec of the Object
	GetSpec() any
	// SetSpec sets the Spec of the Object. It will error if the underlying type is incompatible with the spec type
	SetSpec(any) error
	// GetSubresources returns all known and populated subresouces of the Object, in a map of subresource name -> subresource
	// TODO: should this exist? Originally it was added for arbitrary typed kind unmarshal, which didn't work right anyway
	GetSubresources() map[string]any
	// GetSubresource returns a specific subresource object, or nil if one does not exist. The boolean value is true if the subresource is valid.
	GetSubresource(string) (any, bool)
	// SetSubresource sets a specific subresource by name. If will error if the subresource does not exist, or if the
	// `val` type is incompatible with the subresource type.
	// TODO: should this exist? Originally it was added for arbitrary typed kind unmarshal, which didn't work right anyway
	SetSubresource(key string, val any) error
	// GetStaticMetadata returns the StaticMetadata of the Object
	GetStaticMetadata() StaticMetadata
	// SetStaticMetadata sets the StaticMetadata of the Object. This is equivalent to calling all the SetX methods
	// for each piece of metadata contained in StaticMetadata
	SetStaticMetadata(metadata StaticMetadata)
	// GetCommonMetadata returns the app-sdk CommonMetadata, which is a combination of kubernetes metadata
	// and additional app-sdk-specific metadata
	GetCommonMetadata() CommonMetadata
	// SetCommonMetadata sets the Object metadata fields contained in the provided CommonMetadata
	SetCommonMetadata(CommonMetadata)

	// Copy returns a Deep Copy of the object. This is the equivalent of the runtime.Object DeepCopyObject() method,
	// but one which returns Object instead of runtime.Object.
	Copy() Object
}

Object implements kubernetes' runtime.Object and meta/v1.Object, as well as some additional methods useful for the app-sdk

func CopyObject

func CopyObject(in any) Object

CopyObject is an implementation of the receiver method `Copy()` required for implementing Object. It should be used in your own runtime.Object implementations if you do not wish to implement custom behavior. Example:

func (c *CustomObject) Copy() resource.Object {
    return resource.CopyObject(c)
}

type ObjectMetadataOption

type ObjectMetadataOption func(o SimpleStoreMetadata)

ObjectMetadataOption is a function which updates an ObjectMetadata

func WithLabel

func WithLabel(key, value string) ObjectMetadataOption

WithLabel sets a specific key in the labels of an ObjectMetadata

func WithLabels

func WithLabels(labels map[string]string) ObjectMetadataOption

WithLabels sets the labels of an ObjectMetadata

func WithResourceVersion

func WithResourceVersion(resourceVersion string) ObjectMetadataOption

WithResourceVersion sets the ResourceVersion to the supplied resourceVersion. This allows you to ensure that an update will fail if the version in the store doesn't match the one you supplied.

type PatchOp

type PatchOp string

PatchOp represents an RFC6902 Patch "op" value

type PatchOperation

type PatchOperation struct {
	Path      string  `json:"path"`
	Operation PatchOp `json:"op"`
	Value     any     `json:"value,omitempty"`
}

PatchOperation represents a single patch operation. The patch operation is a JSON Patch operation, as specified by RFC6902 (https://www.rfc-editor.org/rfc/rfc6902)

type PatchOptions

type PatchOptions struct {
}

PatchOptions are the options passed to a Client.Patch call

type PatchRequest

type PatchRequest struct {
	Operations []PatchOperation
}

PatchRequest represents a JSON patch request, which can contain multiple operations. Patch request operations are expected to adhere to the JSON Patch specification laid out by RFC6902, which can be found at https://www.rfc-editor.org/rfc/rfc6902

type RegisterSchemaOptions

type RegisterSchemaOptions struct {
	// UpdateOnConflict will have the manager overwrite the schema definition that currently exists in the system
	// if it already exists. This may impact existing stored resources, depending on the implementation.
	// Use with caution.
	UpdateOnConflict bool
	// NoErrorOnConflict instructs the Manager to return a nil error if the provided Schema already exists in the system,
	// rather than returning a conflict error.
	NoErrorOnConflict bool
	// WaitForAvailability will cause the Manager wait until the resource definition is deemed "available" by the system,
	// or until the context is canceled, after the rest of the Schema registration logic is complete.
	// This may be a no-op for implementations.
	WaitForAvailability bool
}

RegisterSchemaOptions are the options passed to a Manager.RegisterSchema call.

type Schema

type Schema interface {
	// Group returns the Schema group
	Group() string
	// Version returns the Schema version
	Version() string
	// Kind returns the Schema kind
	Kind() string
	// Plural returns the plural name of the Schema kind
	Plural() string
	// ZeroValue returns the "zero-value", "default", or "empty" version of an Object of this Schema
	ZeroValue() Object
	// ZeroListValue returns a ListObject implementation which represents an empty (or appropriately "zero-value")
	// version of the Schema's List.
	ZeroListValue() ListObject
	// Scope returns the scope of the schema object
	Scope() SchemaScope
}

Schema is an interface which represents an object schema for a particular group, version, and kind. It allows a user to create an empty/default instance of the associated go Object for that schema, and encapsulates methods for accessing information about the schema. When combined with read/write methods, it becomes a Kind.

type SchemaGroup

type SchemaGroup interface {
	Schemas() []Schema
}

SchemaGroup represents a group of Schemas. The interface does not require commonality between Schemas, but an implementation may require a relationship. Deprecated: Kinds are now favored over Schemas for usage.

type SchemaScope

type SchemaScope string

type SchemalessClient

type SchemalessClient interface {
	// Get retrieves a resource identified by identifier, and marshals it into `into`
	Get(ctx context.Context, identifier FullIdentifier, into Object) error

	// Create creates a new resource, and marshals the storage response (the created object) into the `into` field
	Create(ctx context.Context, identifier FullIdentifier, obj Object, options CreateOptions, into Object) error

	// Update updates an existing resource, and marshals the updated version into the `into` field
	Update(ctx context.Context, identifier FullIdentifier, obj Object, options UpdateOptions, into Object) error

	// Patch performs a JSON Patch on an object, using the content of the PatchRequest,
	// marshaling the returned (full) object into `into`
	Patch(ctx context.Context, identifier FullIdentifier, path PatchRequest, options PatchOptions, into Object) error

	// Delete deletes a resource identified by identifier
	Delete(ctx context.Context, identifier FullIdentifier) error

	// List lists all resources that satisfy identifier, ignoring `Name`. The response is marshaled into `into`.
	// `exampleListItem` must be provided for proper type unmarshaling, and should be the same kind of object
	// that would be passed to a Get call for `into`
	List(ctx context.Context, identifier FullIdentifier, into ListObject, exampleListItem Object) error

	// Watch watches all resources that satisfy the identifier, ignoring `Name`.
	// The WatchResponse's WatchEvent Objects are created by unmarshaling into an object created by calling
	// example.Copy().
	Watch(ctx context.Context, identifier FullIdentifier, options WatchOptions, example Object) (WatchResponse, error)
}

SchemalessClient is a Schema-agnostic version of the Client interface. All methods require an `into` field, as the Client has no schema knowledge so must do blind deserialization without the benefit of a Schema.ZeroValue(). Passed identifiers are now FullIdentifier, which includes group, version, and kind schema information. Reading/Writing of objects to wire format is left to the discretion of the implementer.

type SimpleMutatingAdmissionController added in v0.9.11

type SimpleMutatingAdmissionController struct {
	// MutateFunc consumes an AdmissionRequest and returns a MutatingResponse containing an updated version
	// of the object passed in the AdmissionRequest, or an error if the request should be rejected.
	// The returned error SHOULD satisfy the AdmissionError interface.
	MutateFunc func(ctx context.Context, request *AdmissionRequest) (*MutatingResponse, error)
}

SimpleMutatingAdmissionController is a simple MutatingAdmissionController which has an exported MutateFunc which is called on the Mutate() method

func (*SimpleMutatingAdmissionController) Mutate added in v0.9.11

Mutate consumes an AdmissionRequest and returns a MutatingResponse or an error

type SimpleSchema

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

SimpleSchema is a simple implementation of Schema. It can be used for constructing simple Schemas, though the easiest way to define a schema is via codegen. TODO: codegen info

func NewSimpleSchema

func NewSimpleSchema(group, version string, zeroVal Object, zeroList ListObject, opts ...SimpleSchemaOption) *SimpleSchema

NewSimpleSchema returns a new SimpleSchema

func (*SimpleSchema) Group

func (s *SimpleSchema) Group() string

Group returns the SimpleSchema's Group

func (*SimpleSchema) Kind

func (s *SimpleSchema) Kind() string

Kind returns the SimpleSchema's Kind

func (*SimpleSchema) Plural

func (s *SimpleSchema) Plural() string

Plural returns the SimpleSchema's Plural

func (*SimpleSchema) Scope

func (s *SimpleSchema) Scope() SchemaScope

Scope returns the SimpleSchema's Scope

func (*SimpleSchema) Version

func (s *SimpleSchema) Version() string

Version returns the SimpleSchema's Version

func (*SimpleSchema) ZeroListValue added in v0.16.0

func (s *SimpleSchema) ZeroListValue() ListObject

ZeroListValue returns a copy the SimpleSchema's zero-valued ListObject instance It can be used directly, as the returned interface is a copy.

func (*SimpleSchema) ZeroValue

func (s *SimpleSchema) ZeroValue() Object

ZeroValue returns a copy the SimpleSchema's zero-valued Object instance It can be used directly, as the returned interface is a copy.

type SimpleSchemaGroup

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

SimpleSchemaGroup collects schemas with the same group and version Deprecated: Kinds are now favored over Schemas for usage. Use KindGroup instead.

func NewSimpleSchemaGroup

func NewSimpleSchemaGroup(group, version string) *SimpleSchemaGroup

NewSimpleSchemaGroup returns a new SimpleSchemaGroup Deprecated: Kinds are now favored over Schemas for usage. Use KindGroup instead.

func (*SimpleSchemaGroup) AddSchema

func (g *SimpleSchemaGroup) AddSchema(zeroVal Object, zeroList ListObject, opts ...SimpleSchemaOption) *SimpleSchema

AddSchema creates a new SimpleSchema with the SimpleSchemaGroup's group and version, adds it to the SimpleSchemaGroup, and returns the created SimpleSchema

func (*SimpleSchemaGroup) Schemas

func (g *SimpleSchemaGroup) Schemas() []Schema

Schemas returns the SimpleSchemaGroup's list of Schemas

type SimpleSchemaOption

type SimpleSchemaOption func(*SimpleSchema)

SimpleSchemaOption is an options function that can be passed to NewSimpleSchema to modify the resulting output

type SimpleStore

type SimpleStore[SpecType any] struct {
	// contains filtered or unexported fields
}

SimpleStore provides an easy key/value store interface for a specific Schema, allowing the user to work with the actual type in the Schema Object's spec, without casting in and out of the Object interface. It should be instantiated with NewSimpleStore. Deprecated: prefer using TypedStore instead

func NewSimpleStore

func NewSimpleStore[SpecType any](kind Kind, generator ClientGenerator) (*SimpleStore[SpecType], error)

NewSimpleStore creates a new SimpleStore for the provided Schema. It will error if the type of the Schema.ZeroValue().SpecObject() does not match the provided SpecType. It will also error if a client cannot be created from the generator, as unlike Store, the client is generated once and reused for all subsequent calls. Deprecated: prefer using TypedStore instead

func (*SimpleStore[T]) Add

func (s *SimpleStore[T]) Add(ctx context.Context, identifier Identifier, obj T, opts ...ObjectMetadataOption) (
	*TypedObject[T, MapSubresourceCatalog], error)

Add creates a new object

func (*SimpleStore[T]) Delete

func (s *SimpleStore[T]) Delete(ctx context.Context, identifier Identifier) error

Delete deletes a resource with the given identifier.

func (*SimpleStore[T]) Get

func (s *SimpleStore[T]) Get(ctx context.Context, identifier Identifier) (*TypedObject[T, MapSubresourceCatalog], error)

Get gets an object with the provided identifier

func (*SimpleStore[T]) List

func (s *SimpleStore[T]) List(ctx context.Context, namespace string, filters ...string) (
	[]TypedObject[T, MapSubresourceCatalog], error)

List returns a list of all resources of the Schema type in the provided namespace, optionally matching the provided filters.

func (*SimpleStore[T]) Update

func (s *SimpleStore[T]) Update(ctx context.Context, identifier Identifier, obj T, opts ...ObjectMetadataOption) (
	*TypedObject[T, MapSubresourceCatalog], error)

Update updates the object with the provided identifier. If the WithResourceVersion option is used, the update will fail if the object's ResourceVersion in the store doesn't match the one provided in WithResourceVersion.

func (*SimpleStore[T]) UpdateSubresource

func (s *SimpleStore[T]) UpdateSubresource(ctx context.Context, identifier Identifier, subresource SubresourceName,
	obj any) (*TypedObject[T, MapSubresourceCatalog], error)

UpdateSubresource updates a named subresource. Type compatibility is not checked for subresources. If the WithResourceVersion option is used, the update will fail if the object's ResourceVersion in the store doesn't match the one provided in WithResourceVersion.

type SimpleStoreMetadata added in v0.15.0

type SimpleStoreMetadata interface {
	metav1.Object
}

SimpleStoreMetadata is a representation of the Metadata used in the TypedObject returned by SimpleStore, and is used for the ObjectMetadataOption argument.

type SimpleStoreObject added in v0.15.0

type SimpleStoreObject[T any] TypedObject[T, map[string]any]

type SimpleValidatingAdmissionController added in v0.9.11

type SimpleValidatingAdmissionController struct {
	// ValidateFunc consumes an AdmissionRequest and returns an error if the request should be rejected.
	// The returned error SHOULD satisfy the AdmissionError interface.
	ValidateFunc func(ctx context.Context, request *AdmissionRequest) error
}

SimpleValidatingAdmissionController is a simple ValidatingAdmissionController which has an exported ValidateFunc which is called on the Validate() method

func (*SimpleValidatingAdmissionController) Validate added in v0.9.11

Validate consumes an AdmissionRequest and returns an error if the request should be rejected

type StaticMetadata

type StaticMetadata struct {
	Group     string `json:"group"`
	Version   string `json:"version"`
	Kind      string `json:"kind"`
	Namespace string `json:"namespace"`
	Name      string `json:"name"`
}

StaticMetadata consists of all non-mutable metadata for an object. It is set in the initial Create call for an Object, then will always remain the same.

func (StaticMetadata) FullIdentifier

func (s StaticMetadata) FullIdentifier() FullIdentifier

FullIdentifier returns a FullIdentifier struct from the StaticMetadata. Plural cannot be inferred so is left empty.

func (StaticMetadata) Identifier

func (s StaticMetadata) Identifier() Identifier

Identifier creates an Identifier struct from the StaticMetadata

type Store

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

Store presents Schema's resource Objects as a simple Key-Value store, abstracting the need to track clients or issue requests. If you wish to directly use a client managed by the store, the Client method returns the client used for a specific Schema.

func NewStore

func NewStore(gen ClientGenerator, groups ...KindCollection) *Store

NewStore creates a new SchemaStore, optionally initially registering all Schemas in the provided SchemaGroups

func (*Store) Add

func (s *Store) Add(ctx context.Context, obj Object) (Object, error)

Add adds the provided resource. This method expects the provided Object's StaticMetadata to have the Name, Namespace, and Kind appropriately set. If they are not, no request will be issued to the underlying client, and an error will be returned.

func (*Store) Client

func (s *Store) Client(kind string) (Client, error)

Client returns a Client for the provided kind, if that kind is tracked by the Store

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, kind string, identifier Identifier) error

Delete deletes a resource with the given Identifier and kind.

func (*Store) ForceDelete added in v0.10.0

func (s *Store) ForceDelete(ctx context.Context, kind string, identifier Identifier) error

ForceDelete deletes a resource with the given Identifier and kind, ignores client 404 errors.

func (*Store) Get

func (s *Store) Get(ctx context.Context, kind string, identifier Identifier) (Object, error)

Get gets a resource with the provided kind and identifier

func (*Store) List

func (s *Store) List(ctx context.Context, kind string, namespace string, filters ...string) (ListObject, error)

List lists all resources of kind in the provided namespace, with optional label filters.

func (*Store) Register

func (s *Store) Register(sch Kind)

Register makes the store aware of a given Schema, and adds it to the list of `kind` values that can be supplied in calls. If a different schema with the same kind already exists, it will be overwritten.

func (*Store) RegisterGroup

func (s *Store) RegisterGroup(group KindCollection)

RegisterGroup calls Register on each Schema in the provided SchemaGroup

func (*Store) SimpleAdd

func (s *Store) SimpleAdd(ctx context.Context, kind string, identifier Identifier, obj Object) (Object, error)

SimpleAdd is a variation of Add that has the caller explicitly supply Identifier and kind as arguments, which will overwrite whatever is set in the obj argument's metadata.

func (*Store) Update

func (s *Store) Update(ctx context.Context, obj Object) (Object, error)

Update updates the provided object. Keep in mind that an Update will completely overwrite the object, so nil or missing values will be removed, not ignored. It is usually best to use the result of a Get call, change the appropriate values, and then call Update with that. The update will fail if no ResourceVersion is provided, or if the ResourceVersion does not match the current one. It returns the updated Object from the storage system.

func (*Store) UpdateSubresource

func (s *Store) UpdateSubresource(
	ctx context.Context, kind string, identifier Identifier, subresourceName SubresourceName, obj any,
) (Object, error)

UpdateSubresource updates a subresource of an object. The provided obj parameter should be the subresource object, not the entire object. No checks are made that the provided object matches the subresource's definition.

func (*Store) Upsert added in v0.10.0

func (s *Store) Upsert(ctx context.Context, obj Object) (Object, error)

Upsert updates/creates the provided object. Keep in mind that an Upsert will completely overwrite the object, so nil or missing values will be removed, not ignored. It is usually best to use the result of a Get call, change the appropriate values, and then call Update with that. The update will fail if no ResourceVersion is provided, or if the ResourceVersion does not match the current one. It returns the updated/created Object from the storage system.

type SubresourceName

type SubresourceName string

SubresourceName is a string wrapper type for CRD subresource names

type TypedList added in v0.15.0

type TypedList[T Object] struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`
	Items           []T `json:"items"`
}

func (*TypedList[T]) Copy added in v0.15.0

func (t *TypedList[T]) Copy() ListObject

Copy creates a copy of the list nolint:revive

func (*TypedList[T]) DeepCopyObject added in v0.15.0

func (t *TypedList[T]) DeepCopyObject() runtime.Object

func (*TypedList[T]) GetItems added in v0.15.0

func (t *TypedList[T]) GetItems() []Object

func (*TypedList[T]) SetItems added in v0.15.0

func (t *TypedList[T]) SetItems(items []Object)

type TypedObject added in v0.15.0

type TypedObject[Spec, SubresourceCatalog any] struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`
	Spec              Spec               `json:"spec"`
	Subresources      SubresourceCatalog `json:"-"`
}

TypedObject is an implementation of Object which has a typed Spec, and an arbitrary set of typed subresources governed by top-level exported fields of the SubresourceCatalog type. It is generally more efficient to use a bespoke Object implementation, or TypedSpecObject or TypedSpecStatusObject, as this type requires the use of more complex generic logic for JSON marshal/unmarshal and the Subresource methods used in Object.

func (*TypedObject[Spec, Sub]) Copy added in v0.15.0

func (t *TypedObject[Spec, Sub]) Copy() Object

Copy creates a copy of the object, using JSON marshaling to copy the spec and status objects. nolint:revive,staticcheck

func (*TypedObject[Spec, Sub]) DeepCopyObject added in v0.15.0

func (t *TypedObject[Spec, Sub]) DeepCopyObject() runtime.Object

func (*TypedObject[Spec, Sub]) GetCommonMetadata added in v0.15.0

func (t *TypedObject[Spec, Sub]) GetCommonMetadata() CommonMetadata

GetCommonMetadata returns CommonMetadata for the object nolint:revive,staticcheck

func (*TypedObject[Spec, Sub]) GetSpec added in v0.15.0

func (t *TypedObject[Spec, Sub]) GetSpec() any

func (*TypedObject[Spec, Sub]) GetStaticMetadata added in v0.15.0

func (t *TypedObject[Spec, Sub]) GetStaticMetadata() StaticMetadata

func (*TypedObject[Spec, Sub]) GetSubresource added in v0.15.0

func (t *TypedObject[Spec, Sub]) GetSubresource(key string) (any, bool)

func (*TypedObject[Spec, Sub]) GetSubresources added in v0.15.0

func (t *TypedObject[Spec, Sub]) GetSubresources() map[string]any

func (*TypedObject[Spec, Sub]) MarshalJSON added in v0.15.0

func (t *TypedObject[Spec, Sub]) MarshalJSON() ([]byte, error)

func (*TypedObject[Spec, Sub]) SetCommonMetadata added in v0.15.0

func (t *TypedObject[Spec, Sub]) SetCommonMetadata(metadata CommonMetadata)

SetCommonMetadata sets metadata in the TypedObject based on the contents of the provided CommonMetadata nolint:dupl

func (*TypedObject[Spec, Sub]) SetSpec added in v0.15.0

func (t *TypedObject[Spec, Sub]) SetSpec(spec any) error

func (*TypedObject[Spec, Sub]) SetStaticMetadata added in v0.15.0

func (t *TypedObject[Spec, Sub]) SetStaticMetadata(metadata StaticMetadata)

func (*TypedObject[Spec, Sub]) SetSubresource added in v0.15.0

func (t *TypedObject[Spec, Sub]) SetSubresource(key string, value any) error

func (*TypedObject[Spec, Sub]) UnmarshalJSON added in v0.15.0

func (t *TypedObject[Spec, Sub]) UnmarshalJSON(data []byte) error

type TypedSpecObject added in v0.15.0

type TypedSpecObject[T any] struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`
	Spec              T `json:"spec"`
}

TypedSpecObject is an implementation of Object which has a typed Spec, and arbitrary untyped subresources, similar to UntypedObject. TODO: should this instead have _no_ subresources, rather than untyped ones?

func (*TypedSpecObject[T]) Copy added in v0.15.0

func (t *TypedSpecObject[T]) Copy() Object

Copy creates a copy of the object. It uses JSON marshaling for copying the spec data. nolint:revive,staticcheck

func (*TypedSpecObject[T]) DeepCopyObject added in v0.15.0

func (t *TypedSpecObject[T]) DeepCopyObject() runtime.Object

func (*TypedSpecObject[T]) GetCommonMetadata added in v0.15.0

func (t *TypedSpecObject[T]) GetCommonMetadata() CommonMetadata

GetCommonMetadata returns CommonMetadata for the object nolint:revive,staticcheck

func (*TypedSpecObject[T]) GetSpec added in v0.15.0

func (t *TypedSpecObject[T]) GetSpec() any

func (*TypedSpecObject[T]) GetStaticMetadata added in v0.15.0

func (t *TypedSpecObject[T]) GetStaticMetadata() StaticMetadata

func (*TypedSpecObject[T]) GetSubresource added in v0.15.0

func (*TypedSpecObject[T]) GetSubresource(_ string) (any, bool)

func (*TypedSpecObject[T]) GetSubresources added in v0.15.0

func (*TypedSpecObject[T]) GetSubresources() map[string]any

func (*TypedSpecObject[T]) SetCommonMetadata added in v0.15.0

func (t *TypedSpecObject[T]) SetCommonMetadata(metadata CommonMetadata)

SetCommonMetadata sets metadata in the TypedSpecObject based on the contents of the provided CommonMetadata nolint:dupl

func (*TypedSpecObject[T]) SetSpec added in v0.15.0

func (t *TypedSpecObject[T]) SetSpec(spec any) error

func (*TypedSpecObject[T]) SetStaticMetadata added in v0.15.0

func (t *TypedSpecObject[T]) SetStaticMetadata(metadata StaticMetadata)

func (*TypedSpecObject[T]) SetSubresource added in v0.15.0

func (*TypedSpecObject[T]) SetSubresource(_ string, _ any) error

type TypedSpecStatusObject added in v0.15.0

type TypedSpecStatusObject[Spec, Status any] struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`
	Spec              Spec   `json:"spec"`
	Status            Status `json:"status"`
}

TypedSpecStatusObject is an implementation of Object which has a typed Spec and Status subresource. Other subresources are not encapsulated by this object implementation.

func (*TypedSpecStatusObject[T, S]) Copy added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) Copy() Object

Copy creates a copy of the object, using JSON marshaling to copy the spec and status objects. nolint:revive,staticcheck

func (*TypedSpecStatusObject[T, S]) DeepCopyObject added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) DeepCopyObject() runtime.Object

func (*TypedSpecStatusObject[T, S]) GetCommonMetadata added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) GetCommonMetadata() CommonMetadata

GetCommonMetadata returns CommonMetadata for the object nolint:revive,staticcheck

func (*TypedSpecStatusObject[T, S]) GetSpec added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) GetSpec() any

func (*TypedSpecStatusObject[T, S]) GetStaticMetadata added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) GetStaticMetadata() StaticMetadata

func (*TypedSpecStatusObject[T, S]) GetSubresource added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) GetSubresource(key string) (any, bool)

func (*TypedSpecStatusObject[T, S]) GetSubresources added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) GetSubresources() map[string]any

func (*TypedSpecStatusObject[T, S]) SetCommonMetadata added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) SetCommonMetadata(metadata CommonMetadata)

SetCommonMetadata sets metadata in the TypedSpecStatusObject based on the contents of the provided CommonMetadata nolint:dupl

func (*TypedSpecStatusObject[T, S]) SetSpec added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) SetSpec(spec any) error

func (*TypedSpecStatusObject[T, S]) SetStaticMetadata added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) SetStaticMetadata(metadata StaticMetadata)

func (*TypedSpecStatusObject[T, S]) SetSubresource added in v0.15.0

func (t *TypedSpecStatusObject[T, S]) SetSubresource(key string, val any) error

type TypedStore

type TypedStore[ObjectType Object] struct {
	// contains filtered or unexported fields
}

TypedStore is a single-Schema store where returned Objects from the underlying client are assumed to be of ObjectType. It is a thin convenience layer over using a raw ClientGenerator.ClientFor()-created Client for a Schema and doing type conversions in-code.

func NewTypedStore

func NewTypedStore[ObjectType Object](kind Kind, generator ClientGenerator) (*TypedStore[ObjectType], error)

NewTypedStore creates a new TypedStore. The ObjectType and Schema.ZeroValue()'s underlying type should match. If they do not, an error is returned.

func (*TypedStore[T]) Add

func (t *TypedStore[T]) Add(ctx context.Context, obj T) (T, error)

Add creates a new resource. obj.GetName() must not be empty, and obj.GetNamespace() cannot be empty for namespace-scoped kinds. If they are not, no request is made to the underlying client, and an error is returned.

func (*TypedStore[T]) Delete

func (t *TypedStore[T]) Delete(ctx context.Context, identifier Identifier) error

Delete deletes a resource with the provided identifier

func (*TypedStore[T]) ForceDelete added in v0.10.0

func (t *TypedStore[T]) ForceDelete(ctx context.Context, identifier Identifier) error

ForceDelete deletes a resource with the provided identifier, ignores 404 errors

func (*TypedStore[T]) Get

func (t *TypedStore[T]) Get(ctx context.Context, identifier Identifier) (T, error)

Get returns a resource with the provided identifier

func (*TypedStore[T]) List

func (t *TypedStore[T]) List(ctx context.Context, namespace string, filters ...string) (*TypedList[T], error)

List lists all resources in the provided namespace, optionally filtered by the provided filters

func (*TypedStore[T]) Update

func (t *TypedStore[T]) Update(ctx context.Context, identifier Identifier, obj T) (T, error)

Update updates an existing resource, and returns the updated version. Keep in mind that an Update will completely overwrite the object, so nil or missing values will be removed, not ignored. It is usually best to use the result of a Get call, change the appropriate values, and then call Update with that. The update will fail if no ResourceVersion is provided, or if the ResourceVersion does not match the current one. It returns the updated Object from the storage system.

func (*TypedStore[T]) UpdateSubresource

func (t *TypedStore[T]) UpdateSubresource(ctx context.Context, identifier Identifier,
	subresource SubresourceName, obj Object) (T, error)

UpdateSubresource updates a subresource of an object. The provided obj parameter must have the specified subresource, and only that subresource will be updated in the storage system.

func (*TypedStore[T]) Upsert added in v0.10.0

func (t *TypedStore[T]) Upsert(ctx context.Context, identifier Identifier, obj T) (T, error)

Upsert updates an existing resource or creates a new one if none exists, and returns the new version. Keep in mind that an Upsert will completely overwrite the object, so nil or missing values will be removed, not ignored. It is usually best to use the result of a Get call, change the appropriate values, and then call Upsert with that. The update will fail if no ResourceVersion is provided, or if the ResourceVersion does not match the current one. It returns the updated Object from the storage system.

type UntypedList added in v0.15.0

type UntypedList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`
	Items           []Object `json:"items"`
}

func (*UntypedList) Copy added in v0.15.0

func (u *UntypedList) Copy() ListObject

func (*UntypedList) DeepCopyObject added in v0.15.0

func (u *UntypedList) DeepCopyObject() runtime.Object

func (*UntypedList) GetItems added in v0.15.0

func (u *UntypedList) GetItems() []Object

func (*UntypedList) SetItems added in v0.15.0

func (u *UntypedList) SetItems(items []Object)

type UntypedObject added in v0.15.0

type UntypedObject struct {
	metav1.TypeMeta
	metav1.ObjectMeta `json:"metadata"`
	// Spec is an untyped map representing the spec data
	Spec map[string]any `json:"spec"`
	// Subresources contains all subresources in raw JSON bytes
	Subresources map[string]json.RawMessage
}

UntypedObject implements Object and represents a generic implementation of an instance of any kubernetes Kind.

func (*UntypedObject) Copy added in v0.15.0

func (u *UntypedObject) Copy() Object

Copy creates a copy of the object, using JSON marshaling to copy the spec, and slice copy for the subresource bytes nolint:revive,staticcheck

func (*UntypedObject) DeepCopyObject added in v0.15.0

func (u *UntypedObject) DeepCopyObject() runtime.Object

func (*UntypedObject) GetCommonMetadata added in v0.15.0

func (u *UntypedObject) GetCommonMetadata() CommonMetadata

GetCommonMetadata returns CommonMetadata for the object nolint:revive,staticcheck

func (*UntypedObject) GetSpec added in v0.15.0

func (u *UntypedObject) GetSpec() any

func (*UntypedObject) GetStaticMetadata added in v0.15.0

func (u *UntypedObject) GetStaticMetadata() StaticMetadata

func (*UntypedObject) GetSubresource added in v0.15.0

func (u *UntypedObject) GetSubresource(key string) (any, bool)

func (*UntypedObject) GetSubresources added in v0.15.0

func (u *UntypedObject) GetSubresources() map[string]any

func (*UntypedObject) MarshalJSON added in v0.15.0

func (u *UntypedObject) MarshalJSON() ([]byte, error)

func (*UntypedObject) SetCommonMetadata added in v0.15.0

func (u *UntypedObject) SetCommonMetadata(metadata CommonMetadata)

SetCommonMetadata sets metadata in the UntypedObject based on the contents of the provided CommonMetadata nolint:dupl

func (*UntypedObject) SetSpec added in v0.15.0

func (u *UntypedObject) SetSpec(spec any) error

func (*UntypedObject) SetStaticMetadata added in v0.15.0

func (u *UntypedObject) SetStaticMetadata(metadata StaticMetadata)

func (*UntypedObject) SetSubresource added in v0.15.0

func (u *UntypedObject) SetSubresource(key string, val any) error

func (*UntypedObject) UnmarshalJSON added in v0.15.0

func (u *UntypedObject) UnmarshalJSON(data []byte) error

type UpdateOptions

type UpdateOptions struct {
	// ResourceVersion is the ResourceVersion to expect from the storage system when performing an update.
	// If there is a mismatch, the update will fail. To have the update succeed regardless of ResourceVersion,
	// leave this field empty.
	ResourceVersion string
	// Subresource can be set to a non-empty subresource field name to update that subresource,
	// instead of the main object
	Subresource string
}

UpdateOptions are the options passed to a Client.Update call

type ValidatingAdmissionController added in v0.9.11

type ValidatingAdmissionController interface {
	// Validate consumes an AdmissionRequest, then returns an error if the request should be denied.
	// The returned error SHOULD satisfy the AdmissionError interface, but callers will fallback
	// to using only the information in a simple error if not.
	Validate(ctx context.Context, request *AdmissionRequest) error
}

ValidatingAdmissionController is an interface that describes any object which should validate admission of a request to manipulate a resource.Object.

type WatchEvent

type WatchEvent struct {
	// EventType is the type of the event
	EventType string
	// Object is the affected object
	Object Object
}

WatchEvent is an event returned from a watch request

type WatchOptions

type WatchOptions struct {
	// ResourceVersion is the resource version to target with the call
	ResourceVersion string
	// ResourceVersionMatch is the way to match against the resource version
	ResourceVersionMatch string
	// EventBufferSize determines the size of the watch event buffer (typically implemented as the channel buffer size)
	// Only nonzero positive values are accepted, implementations will use the default value for cases where
	// EventBufferSize <= 0
	EventBufferSize int
	// LabelFilters are a set of label filter strings applied to watched resources
	LabelFilters []string
}

WatchOptions are the options passed to a Client.Watch call

type WatchResponse

type WatchResponse interface {
	// Stop stops the watch request, and the channel returned by ResultChan
	Stop()
	// WatchEvents returns a channel that receives events from the watch request
	WatchEvents() <-chan WatchEvent
}

WatchResponse is an interface describing the response to a Client.Watch call

type WireFormat

type WireFormat int

WireFormat enumerates values for possible message wire formats. Constants with these values are in this package with a `WireFormat` prefix.

const (
	// WireFormatUnknown is an unknown message wire format.
	WireFormatUnknown WireFormat = iota
	// WireFormatJSON is a JSON message wire format, which should be handle-able by the `json` package.
	// (messages which _contain_ JSON, but are not parsable by the go json package should not be
	// considered to be of the JSON wire format).
	WireFormatJSON
)

Jump to

Keyboard shortcuts

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