infer

package
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 13, 2025 License: Apache-2.0 Imports: 33 Imported by: 138

README

Infer

The infer package provides infrastructure to infer Pulumi component resources, custom resources and functions from go code.

Defining a component resource

Here we will define a component resource that aggregates two custom resources from the random provider. Our component resource will serve a username, derived from either random.RandomId or random.RandomPet. It will also serve a password, derived from random.RandomPassword. We will call the component resource Login.

Full working code for this example can be found in examples/random-login/main.go.

To encapsulate the idea of a new component resource, we define the resource, its inputs and its outputs:

type LoginArgs struct {
	 PasswordLength pulumi.IntPtrInput `pulumi:"passwordLength"`
	 PetName        bool               `pulumi:"petName"`
}

type Login struct {
	 pulumi.ResourceState

	 PasswordLength pulumi.IntPtrInput `pulumi:"passwordLength"`
	 PetName        bool               `pulumi:"petName"`
	 // Outputs
	 Username pulumi.StringOutput `pulumi:"username"`
	 Password pulumi.StringOutput `pulumi:"password"`
}

Each field is tagged with pulumi:"name". Pulumi (and the infer package) only acts on fields with this tag. Pulumi names don't need to match up with with field names, but they should be lowerCamelCase. Fields also need to be exported (capitalized) to interact with Pulumi.

Most fields on components are Inputty or Outputty types, which means they are eventual values. We will make a decision based on PetName, so it is simply a bool. This tells Pulumi that PetName needs to be an immediate value so we can make decisions based on it. Specifically, we decide if we should construct the username based on a random.RandomPet or a random.RandomId.

Now that we have defined the type of the component, we need to define how to actually construct the component resource:

func NewLogin(ctx *pulumi.Context, name string, args LoginArgs, opts ...pulumi.ResourceOption) (
 *Login, error) {
	comp := &Login{}
	err := ctx.RegisterComponentResource(p.GetTypeToken(ctx), name, comp, opts...)
	if err != nil {
		return nil, err
	}
	if args.PetName {
		pet, err := random.NewRandomPet(ctx, name+"-pet", &random.RandomPetArgs{}, pulumi.Parent(comp))
		if err != nil {
			return nil, err
		}
		comp.Username = pet.ID().ToStringOutput()
	} else {
		id, err := random.NewRandomId(ctx, name+"-id", &random.RandomIdArgs{
			ByteLength: pulumi.Int(8),
		}, pulumi.Parent(comp))
		if err != nil {
			return nil, err
		}
		comp.Username = id.ID().ToStringOutput()
	}
	var length pulumi.IntInput = pulumi.Int(16)
	if args.PasswordLength != nil {
		length = args.PasswordLength.ToIntPtrOutput().Elem()
	}
	password, err := random.NewRandomPassword(ctx, name+"-password", &random.RandomPasswordArgs{
		Length: length,
	}, pulumi.Parent(comp))
	if err != nil {
		return nil, err
	}
	comp.Password = password.Result

	return comp, nil
}

This works almost exactly like defining a component resource in Pulumi Go normally does. It is not necessary to call ctx.RegisterComponentResourceOutputs.

The last step in defining the component is serving it. Here we define the provider, telling it that it should serve the Login component.

func main() {
	p, err := infer.NewProviderBuilder().
		WithComponents(
			infer.ComponentF(NewLogin),
		).
		Build()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s", err.Error())
		os.Exit(1)
	}

    p.Run(context.Background(), "example", "0.1.0")
}

This is all it takes to serve a component provider.

Defining a custom resource

As our example of a custom resource, we will implement a custom resource to represent a file in the local file system. This will take us through most of the functionality that inferred custom resource support, including the full CRUD lifecycle.

Full working code for this example can be found in examples/file/main.go.

We first declare the defining struct, its arguments and its state.

type File struct{}

type FileArgs struct {
	Path    string `pulumi:"path,optional"`
	Force   bool   `pulumi:"force,optional"`
	Content string `pulumi:"content"`
}

type FileState struct {
	Path    string `pulumi:"path"`
	Force   bool   `pulumi:"force"`
	Content string `pulumi:"content"`
}

To add descriptions to the new resource, we implement the Annotated interface for File, FileArgs and FileState. This will add descriptions to the resource, its input fields and its output fields.

func (f *File) Annotate(a infer.Annotator) {
	a.Describe(&f, "A file projected into a pulumi resource")
}

func (f *FileArgs) Annotate(a infer.Annotator) {
	a.Describe(&f.Content, "The content of the file.")
	a.Describe(&f.Force, "If an already existing file should be deleted if it exists.")
	a.Describe(&f.Path, "The path of the file. This defaults to the name of the pulumi resource.")
}

func (f *FileState) Annotate(a infer.Annotator) {
	a.Describe(&f.Content, "The content of the file.")
	a.Describe(&f.Force, "If an already existing file should be deleted if it exists.")
	a.Describe(&f.Path, "The path of the file.")
}

To deprecate a resource or field, annotate it with Deprecate:

func (f *FileState) Annotate(a infer.Annotator) {
	a.Deprecate(&f.OldField, "You should prefer to use NewField instead.")

The only mandatory method for a CustomResource is Create:

func (*File) Create(ctx context.Context, req infer.CreateRequest[FileArgs]) (
 infer.CreateResponse[FileState], err error) {
	if !req.Inputs.Force {
		_, err := os.Stat(req.Inputs.Path)
		if !os.IsNotExist(err) {
			return infer.CreateResponse[FileState]{}, fmt.Errorf("file already exists; pass force=true to override")
		}
	}

	if preview { // Don't do the actual creating if in preview
		return infer.CreateResponse[FileState]{ID: req.Inputs.Path}, nil
	}

	f, err := os.Create(req.Inputs.Path)
	if err != nil {
		return infer.CreateResponse[FileState]{}, err
	}
	defer f.Close()
	n, err := f.WriteString(req.Inputs.Content)
	if err != nil {
		return infer.CreateResponse[FileState]{}, err
	}
	if n != len(req.Inputs.Content) {
		return infer.CreateResponse[FileState]{}, fmt.Errorf("only wrote %d/%d bytes", n, len(input.Content))
	}
	return infer.CreateResponse[FileState]{
		ID: req.Inputs.Path,
		Output: FileState{
			Path:    input.Path,
			Force:   input.Force,
			Content: input.Content,
		},
	}, nil
}

We would like the file to be deleted when the custom resource is deleted. We can do that by implementing the Delete method:

func (*File) Delete(ctx context.Context, req infer.DeleteRequest[FileState]) (infer.DeleteResponse, error) {
	err := os.Remove(req.State.Path)
	if os.IsNotExist(err) {
		p.GetLogger(ctx).Warningf("file %q already deleted", req.State.Path)
		err = nil
	}
	return infer.DeleteResponse{}, err
}

Note that we can issue diagnostics to the user via the p.GetLogger(ctx) function. The diagnostic messages are tied to the resource that the method is called on, and pulumi will group them nicely:

Diagnostics:
  fs:index:File (managedFile):
    warning: file "managedFile" already deleted

The next method to implement is Check. We say in the description of FileArgs.Path that it defaults to the name of the resource, but that isn't implement in Create. Instead, we automatically fill the FileArgs.Path field from name if it isn't present in our check implementation.

func (*File) Check(ctx context.Context, req infer.CheckRequest) (
 infer.CheckResponse[FileArgs], error) {
	if _, ok := req.NewInputs["path"]; !ok {
		req.NewInputs["path"] = resource.NewStringProperty(req.Name)
	}
	args, f, err := infer.DefaultCheck[FileArgs](ctx, req.NewInputs)

	return infer.CheckResponse[FileArgs]{
		Inputs:   args,
		Failures: f,
	}, err
}

We still want to make sure our inputs are valid, so we make the adjustment for giving "path" a default value and the call into DefaultCheck, which ensures that all fields are valid given the constraints of their types.

We want to allow our users to change the content of the file they are managing. To allow updates, we need to implement the Update method:

func (*File) Update(ctx context.Context, req infer.UpdateRequest[FileArgs, FileState]) (infer.UpdateResponse[FileState], error) {
	if !req.DryRun && req.State.Content != req.Inputs.Content {
		f, err := os.Create(req.State.Path)
		if err != nil {
			return infer.UpdateResponse[FileState]{}, err
		}
		defer f.Close()
		n, err := f.WriteString(req.Inputs.Content)
		if err != nil {
			return infer.UpdateResponse[FileState]{}, err
		}
		if n != len(req.Inputs.Content) {
			return infer.UpdateResponse[FileState]{}, fmt.Errorf("only wrote %d/%d bytes", n, len(req.Inputs.Content))
		}
	}

	return infer.UpdateResponse[FileState]{
		Output: FileState{
			Path:    req.Inputs.Path,
			Force:   req.Inputs.Force,
			Content: req.Inputs.Content,
		},
	}, nil

}

The above code is pretty straightforward. Note that we don't handle when FileArgs.Path changes, since thats not really an update to an existing file. Its more of a replace operation. To tell pulumi that changes in FileArgs.Content and FileArgs.Force can be handled by updates, but that changes to FileArgs.Path require a replace, we need to override how diff works:

func (*File) Diff(ctx context.Context, req infer.DiffRequest[FileArgs, FileState]) (infer.DiffResponse, error) {
	diff := map[string]p.PropertyDiff{}
	if req.Inputs.Content != req.State.Content {
		diff["content"] = p.PropertyDiff{Kind: p.Update}
	}
	if req.Inputs.Force != req.State.Force {
		diff["force"] = p.PropertyDiff{Kind: p.Update}
	}
	if req.Inputs.Path != req.State.Path {
		diff["path"] = p.PropertyDiff{Kind: p.UpdateReplace}
	}
	return infer.DiffResponse{
		DeleteBeforeReplace: true,
		HasChanges:          len(diff) > 0,
		DetailedDiff:        diff,
	}, nil
}

We check for each field, and if there is a change, we record it. Changes in Inputs.Content and Inputs.Force result in an Update, but changes in Inputs.Path result in an UpdateReplace. Since the id (file path) is globally unique, we also tell Pulumi that it needs to perform deletes before the associated create.

Last but not least, we want to be able to read state from the file system as-is. Unsurprisingly, we do this by implementing yet another method:

func (*File) Read(ctx context.Context, req infer.ReadRequest[FileArgs, FileState]) (infer.ReadResponse[FileArgs, FileState], error) {
	path := req.ID
	byteContent, err := os.ReadFile(path)
	if err != nil {
		return infer.ReadResponse[FileArgs, FileState]{}, err
	}
	content := string(byteContent)
	return infer.ReadResponse[FileArgs, FileState]{
		ID: path,
		Inputs: FileArgs{
			Path:    path,
			Force:   req.Inputs.Force && req.State.Force,
			Content: content,
		},
		State: FileState{
			Path:    path,
			Force:   req.Inputs.Force && req.State.Force,
			Content: content,
		},
	}, nil
}

Here we get a partial view of the id, inputs and state and need to figure out the rest. We return the correct id, args and state.

The last step in defining the resource is serving it. Here we define the provider, telling it that it should serve the File resource.

func main() {
	p, err := infer.NewProviderBuilder().
		WithResources(
			infer.Resource(File{}),
		).
		Build()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s", err.Error())
		os.Exit(1)
	}

    p.Run(context.Background(), "example", "0.1.0")
}

This is an example of a fully functional custom resource, with full participation in the Pulumi lifecycle.

Documentation

Overview

Package infer is a framework to define Pulumi resources and functions derived from go types.

You could say that the Pulumi types are inferred from the Go types.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultCheck

func DefaultCheck[I any](ctx context.Context, inputs property.Map) (I, []p.CheckFailure, error)

DefaultCheck verifies that inputs can deserialize cleanly into I. This is the default validation that is performed when leaving Check unimplemented.

It also adds defaults to inputs as necessary, as defined by [Annotator.SetDefault].

func GetConfig

func GetConfig[T any](ctx context.Context) T

GetConfig retrieves the configuration of this provider.

Note: GetConfig will panic if the type of T does not match the type of the config or if the provider has not supplied a config.

func Provider

func Provider(opts Options) p.Provider

Provider creates a new inferred provider from `opts`.

To customize the resulting provider, including setting resources, functions, config options and other schema metadata, look at the Options struct.

func ProviderErrorf added in v0.16.0

func ProviderErrorf(msg string, a ...any) error

ProviderErrorf create a new ProviderError.

Arguments are formatted with fmt.Errorf.

func Wrap added in v0.8.0

func Wrap(provider p.Provider, opts Options) p.Provider

Wrap wraps a compatible underlying provider in an inferred provider (as described by options).

The resulting provider will respond to resources and functions that are described in `opts`, delegating unknown calls to the underlying provider.

Types

type Annotated

type Annotated interface {
	Annotate(Annotator)
}

Annotated is used to describe the fields of an object or a resource. Annotated can be implemented by `CustomResource`s, the input and output types for all resources and invokes, as well as other structs used the above.

type Annotator

type Annotator interface {
	// Annotate a struct field with a text description.
	Describe(i any, description string)

	// Annotate a struct field with a default value. The default value must be a primitive
	// type in the pulumi type system.
	SetDefault(i any, defaultValue any, env ...string)

	// Set the token of the annotated type.
	//
	// module and name should be valid Pulumi token segments. The package name will be
	// inferred from the provider.
	//
	// For example:
	//
	//	a.SetToken("mymodule", "MyResource")
	//
	// On a provider created with the name "mypkg" will have the token:
	//
	//	mypkg:mymodule:MyResource
	//
	SetToken(module tokens.ModuleName, name tokens.TypeName)

	// Add a type [alias](https://www.pulumi.com/docs/using-pulumi/pulumi-packages/schema/#alias) for
	// this resource.
	//
	// The module and the name will be assembled into a type specifier of the form
	// `mypkg:mymodule:MyResource`, in the same way `SetToken` does.
	AddAlias(module tokens.ModuleName, name tokens.TypeName)

	// Set a deprecation message for a struct field, which officially marks it as deprecated.
	//
	// For example:
	//
	//	func (*s Struct) Annotated(a Annotator) {
	//		a.Deprecate(&s.Field, "field is deprecated")
	//	}
	//
	// To deprecate a resource, object or function, call Deprecate on the struct itself:
	//
	//	func (*s Struct) Annotated(a Annotator) {
	//		a.Deprecate(&s, "Struct is deprecated")
	//	}
	Deprecate(i any, message string)
}

Annotator is used as part of Annotated to describe schema metadata for a resource or type.

The methods of Annotator must be called on pointers to fields of their receivers, or on their receiver itself.

func (*s Struct) Annotated(a Annotator) {
	a.Describe(&s, "A struct")            // Legal
	a.Describe(&s.field1, "A field")      // Legal
	a.Describe(s.field2, "A field")       // Not legal, since the pointer is missing.
	otherS := &Struct{}
	a.Describe(&otherS.field1, "A field") // Not legal, since describe is not called on its receiver.
}

type CheckRequest added in v1.0.0

type CheckRequest struct {
	// The resource name.
	Name string
	// The old resource inputs.
	OldInputs property.Map
	// The new resource inputs.
	NewInputs property.Map
}

CheckRequest contains all the parameters for a Check operation.

type CheckResponse added in v1.0.0

type CheckResponse[I any] struct {
	// The validated inputs.
	Inputs I
	// Any validation failures encountered.
	Failures []p.CheckFailure
}

CheckResponse contains all the results from a Check operation

type ComponentFn added in v0.25.0

type ComponentFn[A any, R pulumi.ComponentResource] = func(
	ctx *pulumi.Context, name string, args A, opts ...pulumi.ResourceOption,
) (R, error)

ComponentFn describes the type signature of a Pulumi component resource defined in Go.

type ComponentResource

type ComponentResource[I any, O pulumi.ComponentResource] interface {
	// Construct a component resource
	//
	// ctx.RegisterResource needs to be called, but ctx.RegisterOutputs does not need to
	// be called.
	Construct(ctx *pulumi.Context, name, typ string, args I, opts pulumi.ResourceOption) (O, error)
}

ComponentResource may be turned into an InferredComponent with Component.

type Crawler

type Crawler func(
	t reflect.Type, isReference bool,
	fieldInfo *introspect.FieldTag,
	parent, field string,
) (drill bool, err error)

type CreateRequest added in v1.0.0

type CreateRequest[I any] struct {
	// The resource name.
	Name string
	// The resource inputs.
	Inputs I
	// Whether this is a preview operation.
	DryRun bool
}

CreateRequest contains all the parameters for a Create operation

type CreateResponse added in v1.0.0

type CreateResponse[O any] struct {
	// The provider assigned unique ID of the created resource.
	ID string
	// The output state of the resource to checkpoint.
	Output O
}

CreateResponse contains all the results from a Create operation

type CustomCheck

type CustomCheck[I any] interface {
	// Check validates the inputs for a resource.
	Check(ctx context.Context, req CheckRequest) (CheckResponse[I], error)
}

CustomCheck describes a resource that understands how to check its inputs.

By default, infer handles checks by ensuring that inputs de-serialize correctly, applying default values and secrets. You can wrap the default behavior of Check by calling DefaultCheck inside of your custom Check implementation.

This is where you can extend that behavior. The returned input is given to subsequent calls to `Create` and `Update`.

CheckRequest contains all the parameters for a Check operation.

type CustomConfigure added in v0.10.1

type CustomConfigure interface {
	// Configure the provider.
	//
	// This method will only be called once per provider process.
	//
	// By the time Configure is called, the receiver will be fully hydrated.
	//
	// Changes to the receiver will not be saved in state. For normalizing inputs see
	// [CustomCheck].
	Configure(ctx context.Context) error
}

CustomConfigure describes a provider that requires custom configuration before running.

This interface should be implemented by reference to allow setting private fields on its receiver.

type CustomCreate added in v0.16.0

type CustomCreate[I, O any] interface {
	Create(ctx context.Context, req CreateRequest[I]) (CreateResponse[O], error)
}

type CustomDelete

type CustomDelete[O any] interface {
	// Delete is called before a resource is removed from pulumi state.
	Delete(ctx context.Context, req DeleteRequest[O]) (DeleteResponse, error)
}

CustomDelete describes a resource that knows how to delete itself.

If a resource does not implement Delete, no code will be run on resource deletion.

type CustomDiff

type CustomDiff[I, O any] interface {
	Diff(ctx context.Context, req DiffRequest[I, O]) (DiffResponse, error)
}

CustomDiff describes a resource that understands how to diff itself given a new set of inputs.

By default, infer handles diffs by structural equality among inputs. If CustomUpdate is implemented, changes will result in updates. Otherwise changes will result in replaces.

Example: TODO - Indicate replacements for certain changes but not others.

type CustomRead

type CustomRead[I, O any] interface {
	Read(ctx context.Context, req ReadRequest[I, O]) (ReadResponse[I, O], error)
}

CustomRead describes resource that can recover its state from the provider.

If CustomRead is not implemented, it will default to checking that the inputs and state fit into I and O respectively. If they do, then the values will be returned as is. Otherwise an error will be returned.

Example: TODO - Probably something to do with the file system.

type CustomResource

type CustomResource[I, O any] interface {
	// All custom resources must be able to be created.
	CustomCreate[I, O]
}

CustomResource is a [custom resource](https://www.pulumi.com/docs/concepts/resources/) inferred from code. This is the minimum requirement for defining a new custom resource.

This interface should be implemented by the resource controller, with `I` the resource inputs and `O` the full set of resource fields. It is recommended that `O` is a superset of `I`, but it is not strictly required. The fields of `I` and `O` should consist of non-pulumi types i.e. `string` and `int` instead of `pulumi.StringInput` and `pulumi.IntOutput`.

The behavior of a CustomResource resource can be extended by implementing any of the following interfaces on the resource controller:

- CustomCheck - CustomDiff - CustomUpdate - CustomRead - CustomDelete - CustomStateMigrations - Annotated

Example:

type MyResource struct{}

type MyResourceInputs struct {
	MyString string `pulumi:"myString"`
	OptionalInt *int `pulumi:"myInt,optional"`
}

type MyResourceOutputs struct {
	MyResourceInputs
	Result string `pulumi:"result"`
}

func (*MyResource) Create(
	ctx context.Context, req infer.CreateRequest[MyResourceInputs],
) (infer.CreateResponse[MyResourceOutputs], error) {
	id := req.Inputs.MyString + ".id"
	if req.DryRun {
		return infer.CreateResponse[MyResourceOutputs]{
			ID: id,
			Output: MyResourceOutputs{MyResourceInputs: inputs},
		}, nil
	}

	result := req.Inputs.MyString
	if req.Inputs.OptionalInt != nil {
		result = fmt.Sprintf("%s.%d", result, *req.Inputs.OptionalInt)
	}

	return infer.CreateResponse[MyResourceOutputs]{
				ID: id,
				Output: MyResourceOutputs{inputs, result},
			}, nil
}

type CustomStateMigrations added in v0.16.0

type CustomStateMigrations[O any] interface {
	// StateMigrations is the list of know migrations.
	//
	// Each migration should return a valid State object.
	//
	// The first migration to return a non-nil Result will be used.
	StateMigrations(ctx context.Context) []StateMigrationFunc[O]
}

type CustomUpdate

type CustomUpdate[I, O any] interface {
	Update(ctx context.Context, req UpdateRequest[I, O]) (UpdateResponse[O], error)
}

CustomUpdate descibes a resource that can adapt to new inputs with a delete and replace.

There is no default behavior for CustomUpdate.

Here the old state (as returned by Create or Update) as well as the new inputs are passed. Update should return the new state of the resource. If preview is true, then the update is part of `pulumi preview` and no changes should be made.

Example:

TODO

type DeleteRequest added in v1.0.0

type DeleteRequest[O any] struct {
	// The resource ID.
	ID string
	// The current resource state.
	State O
}

DeleteRequest contains all the parameters for a Delete operation

type DeleteResponse added in v1.0.0

type DeleteResponse struct {
}

DeleteResponse contains all the results from a Delete operation

type DiffRequest added in v1.0.0

type DiffRequest[I, O any] struct {
	// The resource ID.
	ID string
	// The old resource state.
	State O
	// The new resource inputs.
	Inputs I
}

DiffRequest contains all the parameters for a Diff operation.

type DiffResponse added in v1.0.0

type DiffResponse = p.DiffResponse

DiffResponse contains all the results from a Diff operation.

type Enum

type Enum[T EnumKind] interface {
	// A list of all allowed values for the enum.
	Values() []EnumValue[T]
}

Enum is an enum in the Pulumi type system.

type EnumKind

type EnumKind interface {
	~string | ~float64 | ~bool | ~int
}

EnumKind is the set of allowed underlying values for Enum.

type EnumValue

type EnumValue[T any] struct {
	Name        string
	Value       T
	Description string
}

An EnumValue represents an allowed value for an Enum.

type ExplicitDependencies

type ExplicitDependencies[I, O any] interface {
	// WireDependencies specifies the dependencies between inputs and outputs.
	WireDependencies(f FieldSelector, args *I, state *O)
}

ExplicitDependencies describes a custom resource with the dataflow between its arguments (`I`) and outputs (`O`) specified. If a CustomResource implements ExplicitDependencies then WireDependencies will be called for each Create and Update call with `args` and `state` holding the values they will have for that call.

If ExplicitDependencies is not implemented, it is assumed that all outputs depend on all inputs.

type FieldSelector

type FieldSelector interface {
	// Create an input field. The argument to InputField must be a pointer to a field of
	// the associated input type I.
	//
	// For example:
	// “`go
	// func (r *MyResource) WireDependencies(f infer.FieldSelector, args *MyArgs, state *MyState) {
	//   f.InputField(&args.Field)
	// }
	// “`
	InputField(any) InputField
	// Create an output field. The argument to OutputField must be a pointer to a field of
	// the associated output type O.
	//
	// For example:
	// “`go
	// func (r *MyResource) WireDependencies(f infer.FieldSelector, args *MyArgs, state *MyState) {
	//   f.OutputField(&state.Field)
	// }
	// “`
	OutputField(any) OutputField
	// contains filtered or unexported methods
}

FieldSelector is used to describe the relationship between fields.

type Fn

type Fn[I any, O any] interface {
	// Fn is a function (also called an "invoke" or "Provider Function") inferred from code. `I` is the function input,
	// and `O` is the function output. Both must be structs.
	// See: https://www.pulumi.com/docs/iac/concepts/resources/functions/#provider-functions
	Invoke(ctx context.Context, req FunctionRequest[I]) (resp FunctionResponse[O], err error)
}

Fn is a function (also called fnvoke) inferred from code. `I` is the function input, and `O` is the function output. Both must be structs.

type FunctionRequest added in v1.0.0

type FunctionRequest[I any] struct {
	// Input contains the function input arguments.
	Input I
}

FunctionRequest wraps the input type for a function call

type FunctionResponse added in v1.0.0

type FunctionResponse[O any] struct {
	// Output contains the function result.
	Output O
}

FunctionResponse wraps the output type for a function call

type InferredComponent

type InferredComponent interface {
	t.ComponentResource
	schema.Resource
	// contains filtered or unexported methods
}

InferredComponent is a component resource inferred from code.

To create an InferredComponent, call the ComponentF function.

func Component

func Component[R ComponentResource[I, O], I any, O pulumi.ComponentResource](rsc R) InferredComponent

Component defines a component resource from go code. Here `R` is the component resource anchor, `I` describes its inputs and `O` its outputs. To add descriptions to `R`, `I` and `O`, see the `Annotated` trait defined in this module.

func ComponentF added in v1.0.0

func ComponentF[A any, O pulumi.ComponentResource, F ComponentFn[A, O]](fn F) InferredComponent

ComponentF creates an InferredComponent using functions and types that an existing Pulumi component program would have implemented.

fn is the function you would use to construct the program.

See: https://www.pulumi.com/docs/iac/concepts/resources/components/#authoring-a-new-component-resource.

type InferredConfig

type InferredConfig interface {
	schema.Resource
	// contains filtered or unexported methods
}

func Config

func Config[T any](cfg T) InferredConfig

Config turns an object into a description for the provider configuration.

`T` has the same properties as an input or output type for a custom resource, and is responsive to the same interfaces.

`T` can implement CustomDiff and CustomCheck and CustomConfigure and Annotated.

type InferredFunction

type InferredFunction interface {
	t.Invoke
	schema.Function
	// contains filtered or unexported methods
}

InferredFunction is a function inferred from code. See Function for creating a InferredFunction.

func Function

func Function[F Fn[I, O], I, O any](fnc F) InferredFunction

Function infers a function from `F`, which maps `I` to `O`.

type InferredResource

type InferredResource interface {
	t.CustomResource
	schema.Resource
	// contains filtered or unexported methods
}

InferredResource is a resource inferred by the Resource function.

This interface cannot be implemented directly. Instead consult the Resource function.

func Resource

func Resource[R CustomResource[I, O], I, O any](rsc R) InferredResource

Resource creates a new InferredResource, where `R` is the resource controller, `I` is the resources inputs and `O` is the resources outputs.

type InputField

type InputField interface {

	// Only wire secretness, not computedness.
	Secret() InputField

	// Only flow computedness, not secretness.
	Computed() InputField
	// contains filtered or unexported methods
}

InputField represents an argument/input field to apply metadata to.

See FieldSelector for details on usage.

type MigrationResult added in v0.16.0

type MigrationResult[T any] struct {
	// Result is the result of the migration.
	//
	// If Result is nil, then the migration is considered to have been unnecessary.
	//
	// If Result is non-nil, then the migration is considered to have completed and
	// the new value state value will be *Result.
	Result *T
}

MigrationResult represents the result of a migration.

type Options added in v0.8.0

type Options struct {
	// Metadata describes provider level metadata for the schema.
	//
	// Look at [schema.Metadata] to see the set of configurable options.
	//
	// It does not contain runtime details for the provider.
	schema.Metadata

	// The set of custom resources served by the provider.
	//
	// To create an [InferredResource], use [Resource].
	Resources []InferredResource

	// The set of component resources served by the provider.
	//
	// To create an [InferredComponent], use [Component].
	Components []InferredComponent

	// The set of functions served by the provider.
	//
	// To create an [InferredFunction], use [Function].
	Functions []InferredFunction

	// The config used by the provider, if any.
	//
	// To create an [InferredConfig], use [Config].
	Config InferredConfig

	// ModuleMap provides a mapping between go modules and pulumi modules.
	//
	// For example, given a provider `pkg` with defines resources `foo.Foo`, `foo.Bar`, and
	// `fizz.Buzz` the provider will expose resources at `pkg:foo:Foo`, `pkg:foo:Bar` and
	// `pkg:fizz:Buzz`. Adding
	//
	//	`opts.ModuleMap = map[tokens.ModuleName]tokens.ModuleName{"foo": "bar"}`
	//
	// will instead result in exposing the same resources at `pkg:bar:Foo`, `pkg:bar:Bar` and
	// `pkg:fizz:Buzz`.
	ModuleMap map[tokens.ModuleName]tokens.ModuleName
	// contains filtered or unexported fields
}

Options to configure an inferred provider.

See Provider to turn a set of Options into a p.Provider.

type OutputField

type OutputField interface {
	// Specify that a state (output) field is always secret, regardless of its dependencies.
	AlwaysSecret()
	// Specify that a state (output) field is never secret, regardless of its dependencies.
	NeverSecret()
	// Specify that a state (output) field is always known, regardless of dependencies
	// or preview.
	AlwaysKnown()
	// Specify that a state (output) Field uses data from some args (input) Fields.
	DependsOn(dependencies ...InputField)
	// contains filtered or unexported methods
}

OutputField represents an output/state field to apply metadata to.

See FieldSelector for details on usage.

type ProviderBuilder added in v0.25.0

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

func NewProviderBuilder added in v0.25.0

func NewProviderBuilder() *ProviderBuilder

NewProviderBuilder creates an inferred provider which fills as many defaults as possible.

A base set of defaults are provided to create a minimal provider configuration. Further customization can be done by chaining method calls on the returned ProviderBuilder object.

This is an example of how to create a simple provider with a single component resource:

type RandomComponent struct {
    pulumi.ResourceState
    RandomComponentArgs

    Password pulumi.StringOutput `pulumi:"password"`
}

type RandomComponentArgs struct {
    Length pulumi.IntInput `pulumi:"length"`
}

func NewMyComponent(ctx *pulumi.Context, name string,
    compArgs RandomComponentArgs, opts ...pulumi.ResourceOption) (*RandomComponent, error) {
    // Define your component constructor logic here.
}

func main() {
    p, _ := infer.NewProviderBuilder().
        WithComponents(
            infer.ComponentF(NewMyComponent),
        ).
        Build()
    p.Run(context.Background(), "go-components", "v0.0.1")
}

Please note that the initial defaults provided by this function may change with future releases of this framework. Currently, we are setting the following defaults:

- LanguageMap: A map of language-specific metadata that is used to generate the SDKs for the provider.

func (*ProviderBuilder) Build added in v1.0.0

func (pb *ProviderBuilder) Build() (provider.Provider, error)

Build builds the provider options and validates them., and runs the provider.

func (*ProviderBuilder) BuildOptions added in v0.25.0

func (pb *ProviderBuilder) BuildOptions() Options

BuildOptions builds an Options object from the provider builder configuration. This is useful when a user wants to have more control over the provider creation process.

func (*ProviderBuilder) WithComponents added in v0.25.0

func (pb *ProviderBuilder) WithComponents(components ...InferredComponent) *ProviderBuilder

WithComponents adds the given components to the provider.

func (*ProviderBuilder) WithConfig added in v0.25.0

func (pb *ProviderBuilder) WithConfig(config InferredConfig) *ProviderBuilder

WithConfig adds the given config to the provider.

func (*ProviderBuilder) WithDescription added in v0.25.0

func (pb *ProviderBuilder) WithDescription(description string) *ProviderBuilder

WithDescription sets the description for the provider.

func (*ProviderBuilder) WithDisplayName added in v0.25.0

func (pb *ProviderBuilder) WithDisplayName(displayName string) *ProviderBuilder

WithDisplayName sets the display name for the provider.

func (*ProviderBuilder) WithFunctions added in v0.25.0

func (pb *ProviderBuilder) WithFunctions(functions ...InferredFunction) *ProviderBuilder

WithFunctions adds the given functions to the provider.

func (*ProviderBuilder) WithGoImportPath added in v1.0.0

func (pb *ProviderBuilder) WithGoImportPath(path string) *ProviderBuilder

WithGoImportPath sets the base import path for the provider's generated SDK.

func (*ProviderBuilder) WithHomepage added in v0.25.0

func (pb *ProviderBuilder) WithHomepage(homepage string) *ProviderBuilder

WithHomepage sets the homepage field in the provider metadata.

func (*ProviderBuilder) WithKeywords added in v0.25.0

func (pb *ProviderBuilder) WithKeywords(keywords ...string) *ProviderBuilder

WithKeywords adds the specified keywords to the provider's metadata. These keywords can be used to improve discoverability of the provider.

func (*ProviderBuilder) WithLanguageMap added in v0.25.0

func (pb *ProviderBuilder) WithLanguageMap(languageMap map[string]any) *ProviderBuilder

WithLanguageMap sets the language map in the provider's metadata. The language map is a mapping of language names to language-specific metadata. This is used to customize how the provider is exposed in different languages.

func (*ProviderBuilder) WithLicense added in v0.25.0

func (pb *ProviderBuilder) WithLicense(license string) *ProviderBuilder

WithLicense sets the license for the provider.

func (*ProviderBuilder) WithLogoURL added in v0.25.0

func (pb *ProviderBuilder) WithLogoURL(logoURL string) *ProviderBuilder

WithLogoURL sets the logo URL for the provider.

func (*ProviderBuilder) WithModuleMap added in v0.25.0

func (pb *ProviderBuilder) WithModuleMap(moduleMap map[tokens.ModuleName]tokens.ModuleName) *ProviderBuilder

WithModuleMap adds the given module map to the provider.

func (*ProviderBuilder) WithNamespace added in v0.25.0

func (pb *ProviderBuilder) WithNamespace(namespace string) *ProviderBuilder

WithNamespace sets the provider namespace.

func (*ProviderBuilder) WithPluginDownloadURL added in v0.25.0

func (pb *ProviderBuilder) WithPluginDownloadURL(pluginDownloadURL string) *ProviderBuilder

WithPluginDownloadURL sets the URL from which to download the provider's plugin.

func (*ProviderBuilder) WithPublisher added in v0.25.0

func (pb *ProviderBuilder) WithPublisher(publisher string) *ProviderBuilder

WithPublisher sets the publisher name for the provider.

func (*ProviderBuilder) WithRepository added in v0.25.0

func (pb *ProviderBuilder) WithRepository(repository string) *ProviderBuilder

WithRepository sets the repository for the provider.

func (*ProviderBuilder) WithResources added in v0.25.0

func (pb *ProviderBuilder) WithResources(resources ...InferredResource) *ProviderBuilder

WithResources adds the given custom resources to the provider.

func (*ProviderBuilder) WithWrapped added in v1.0.0

func (pb *ProviderBuilder) WithWrapped(provider provider.Provider) *ProviderBuilder

WithWrapped wraps another provider.

type ProviderError added in v0.16.0

type ProviderError struct {
	Inner error
}

ProviderError indicates a bug in the provider implementation.

When displayed, ProviderError tells the user that the issue was internal and should be reported.

func (ProviderError) Error added in v0.16.0

func (err ProviderError) Error() string

type ReadRequest added in v1.0.0

type ReadRequest[I, O any] struct {
	// The resource ID.
	ID string
	// The resource inputs.
	Inputs I
	// The current resource state.
	State O
}

ReadRequest contains all the parameters for a Read operation

type ReadResponse added in v1.0.0

type ReadResponse[I, O any] struct {
	// The canonical ID of the resource.
	ID string
	// The normalized inputs.
	Inputs I
	// The normalized state.
	State O
}

ReadResponse contains all the results from a Read operation

type ResourceInitFailedError added in v0.16.0

type ResourceInitFailedError struct {
	Reasons []string
}

ResourceInitFailedError indicates that the resource was created but failed to initialize.

This error is treated specially in Create, Update and Read. If the returner error for a Create, Update or Read returns true for Errors.Is, state is updated to correspond to the accompanying state, the resource will be considered created, and the next call will be Update with the new state.

func (*Team) Create(
	ctx context.Context, name string, input TeamInput, preview bool,
) (id string, output TeamState, err error) {
	team, err := GetConfig(ctx).Client.CreateTeam(ctx,
		input.OrganizationName, input.Name,
		input.TeamType, input.DisplayName,
		input.Description, input.GithubTeamId)
	if err != nil {
		return "", TeamState{}, fmt.Errorf("error creating team '%s': %w", input.Name, err)
	}

	if membersAdded, err := addMembers(team, input.Members); err != nil {
		return TeamState{
			Input: input,
			Members: membersAdded,
		}, infer.ResourceInitFailedError{Reasons: []string{
			fmt.Sprintf("Failed to add members: %s", err),
		}}
	}

	return TeamState{input, input.Members}, nil
}

If the the above example errors with infer.ResourceInitFailedError, the next Update will be called with `state` equal to what was returned alongside infer.ResourceInitFailedError.

func (ResourceInitFailedError) Error added in v0.16.0

func (err ResourceInitFailedError) Error() string

type StateMigrationFunc added in v0.16.0

type StateMigrationFunc[New any] interface {
	// contains filtered or unexported methods
}

StateMigrationFunc represents a stateless mapping from an old state shape to a new state shape. Each StateMigrationFunc is parameterized by the shape of the type it produces, ensuring that all successful migrations end up in a valid state.

To create a StateMigrationFunc, use StateMigration.

func StateMigration added in v0.16.0

func StateMigration[Old, New any, F func(context.Context, Old) (MigrationResult[New], error)](
	f F,
) StateMigrationFunc[New]

StateMigration creates a mapping from an old state shape (type Old) to a new state shape (type New).

If Old = resource.PropertyMap, then the migration is always run.

Example:

type MyResource struct{}

type MyInput struct{}

type MyStateV1 struct {
	SomeInt *int `pulumi:"someInt,optional"`
}

type MyStateV2 struct {
	AString string `pulumi:"aString"`
	AInt    *int   `pulumi:"aInt,optional"`
}

func migrateFromV1(ctx context.Context, v1 StateV1) (infer.MigrationResult[MigrateStateV2], error) {
	return infer.MigrationResult[MigrateStateV2]{
		Result: &MigrateStateV2{
			AString: "default-string", // Add a new required field
			AInt: v1.SomeInt, // Rename an existing field
		},
	}, nil
}

// Associate your migration with the resource it encapsulates.
func (*MyResource) StateMigrations(context.Context) []infer.StateMigrationFunc[MigrateStateV2] {
	return []infer.StateMigrationFunc[MigrateStateV2]{
		infer.StateMigration(migrateFromV1),
	}
}

type UpdateRequest added in v1.0.0

type UpdateRequest[I, O any] struct {
	// The resource ID.
	ID string
	// The old resource state.
	State O
	// The new resource inputs.
	Inputs I
	// Whether this is a preview operation.
	DryRun bool
}

UpdateRequest contains all the parameters for an Update operation

type UpdateResponse added in v1.0.0

type UpdateResponse[O any] struct {
	// The output state of the resource to checkpoint.
	Output O
}

UpdateResponse contains all the results from an Update operation

Directories

Path Synopsis
internal
ende
Package ende - ENcoding and DEcoding resource.Property* values
Package ende - ENcoding and DEcoding resource.Property* values
Package tests is a generated GoMock package.
Package tests is a generated GoMock package.
Package types provides ancillary types for use with github.com/pulumi/pulumi-go-provider/infer.
Package types provides ancillary types for use with github.com/pulumi/pulumi-go-provider/infer.

Jump to

Keyboard shortcuts

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