mirror of https://github.com/pulumi/pulumi.git
918 lines
29 KiB
Go
918 lines
29 KiB
Go
// Copyright 2016-2021, Pulumi Corporation.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package pulumi
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/slice"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/internal"
|
|
)
|
|
|
|
type (
|
|
// ID is a unique identifier assigned by a resource provider to a resource.
|
|
ID string
|
|
// URN is an automatically generated logical URN, used to stably identify resources.
|
|
URN string
|
|
)
|
|
|
|
var (
|
|
resourceStateType = reflect.TypeOf(ResourceState{})
|
|
customResourceStateType = reflect.TypeOf(CustomResourceState{})
|
|
providerResourceStateType = reflect.TypeOf(ProviderResourceState{})
|
|
)
|
|
|
|
// This type alias is a hack to embed the internal.ResourceState type
|
|
// into pulumi.ResourceState without exporting the field to the public API.
|
|
//
|
|
//nolint:unused
|
|
type internalResourceState = internal.ResourceState
|
|
|
|
// ResourceState is the base
|
|
type ResourceState struct {
|
|
// internalResourceState marks this ResourceState as a resource
|
|
// recognized by the internal package.
|
|
internalResourceState
|
|
|
|
m sync.RWMutex
|
|
|
|
urn URNOutput `pulumi:"urn"`
|
|
|
|
rawOutputs Output
|
|
children resourceSet
|
|
providers map[string]ProviderResource
|
|
provider ProviderResource
|
|
version string
|
|
pluginDownloadURL string
|
|
aliases []URNOutput
|
|
name string
|
|
transformations []ResourceTransformation
|
|
|
|
keepDep bool
|
|
}
|
|
|
|
var _ Resource = (*ResourceState)(nil)
|
|
|
|
func (s *ResourceState) URN() URNOutput {
|
|
return s.urn
|
|
}
|
|
|
|
func (s *ResourceState) GetProvider(token string) ProviderResource {
|
|
return s.providers[getPackage(token)]
|
|
}
|
|
|
|
// This is an internal method and future versions of the sdk may not support this API.
|
|
//
|
|
// InternalGetRawOutputs obtains the full PropertyMap returned during resource registration,
|
|
// allowing a caller of RegisterResource to obtain directly information about the outputs and their
|
|
// known and secret attributes.
|
|
func InternalGetRawOutputs(res *ResourceState) Output {
|
|
return res.rawOutputs
|
|
}
|
|
|
|
func (s *ResourceState) getChildren() []Resource {
|
|
s.m.RLock()
|
|
defer s.m.RUnlock()
|
|
|
|
var children []Resource
|
|
if len(s.children) != 0 {
|
|
children = slice.Prealloc[Resource](len(s.children))
|
|
for r := range s.children {
|
|
children = append(children, r)
|
|
}
|
|
}
|
|
return children
|
|
}
|
|
|
|
func (s *ResourceState) addChild(r Resource) {
|
|
s.m.Lock()
|
|
defer s.m.Unlock()
|
|
|
|
if s.children == nil {
|
|
s.children = resourceSet{}
|
|
}
|
|
s.children.add(r)
|
|
}
|
|
|
|
func (s *ResourceState) getProviders() map[string]ProviderResource {
|
|
return s.providers
|
|
}
|
|
|
|
func (s *ResourceState) getProvider() ProviderResource {
|
|
return s.provider
|
|
}
|
|
|
|
func (s *ResourceState) getVersion() string {
|
|
return s.version
|
|
}
|
|
|
|
func (s *ResourceState) getPluginDownloadURL() string {
|
|
return s.pluginDownloadURL
|
|
}
|
|
|
|
func (s *ResourceState) getAliases() []URNOutput {
|
|
return s.aliases
|
|
}
|
|
|
|
func (s *ResourceState) getName() string {
|
|
return s.name
|
|
}
|
|
|
|
func (s *ResourceState) getTransformations() []ResourceTransformation {
|
|
return s.transformations
|
|
}
|
|
|
|
func (s *ResourceState) addTransformation(t ResourceTransformation) {
|
|
s.transformations = append(s.transformations, t)
|
|
}
|
|
|
|
func (s *ResourceState) setKeepDependency() {
|
|
s.keepDep = true
|
|
}
|
|
|
|
func (s *ResourceState) keepDependency() bool {
|
|
return s.keepDep
|
|
}
|
|
|
|
func (ctx *Context) newDependencyResource(urn URN) Resource {
|
|
var res ResourceState
|
|
res.urn.OutputState = ctx.newOutputState(res.urn.ElementType(), &res)
|
|
internal.ResolveOutput(res.urn, urn, true, false, resourcesToInternal(nil))
|
|
res.keepDep = true
|
|
return &res
|
|
}
|
|
|
|
type CustomResourceState struct {
|
|
ResourceState
|
|
|
|
id IDOutput `pulumi:"id"`
|
|
}
|
|
|
|
func (s *CustomResourceState) ID() IDOutput {
|
|
return s.id
|
|
}
|
|
|
|
func (*CustomResourceState) isCustomResource() {}
|
|
|
|
func (ctx *Context) newDependencyCustomResource(urn URN, id ID) CustomResource {
|
|
var res CustomResourceState
|
|
res.urn.OutputState = ctx.newOutputState(res.urn.ElementType(), &res)
|
|
internal.ResolveOutput(res.urn, urn, true, false, resourcesToInternal(nil))
|
|
res.id.OutputState = ctx.newOutputState(res.id.ElementType(), &res)
|
|
internal.ResolveOutput(res.id, id, id != "", false, resourcesToInternal(nil))
|
|
return &res
|
|
}
|
|
|
|
type ProviderResourceState struct {
|
|
CustomResourceState
|
|
|
|
pkg string
|
|
}
|
|
|
|
func (s *ProviderResourceState) getPackage() string {
|
|
return s.pkg
|
|
}
|
|
|
|
func (ctx *Context) newDependencyProviderResource(urn URN, id ID) ProviderResource {
|
|
var res ProviderResourceState
|
|
res.urn.OutputState = ctx.newOutputState(res.urn.ElementType(), &res)
|
|
res.id.OutputState = ctx.newOutputState(res.id.ElementType(), &res)
|
|
internal.ResolveOutput(res.urn, urn, true, false, resourcesToInternal(nil))
|
|
internal.ResolveOutput(res.id, id, id != "", false, resourcesToInternal(nil))
|
|
res.pkg = string(resource.URN(urn).Type().Name())
|
|
return &res
|
|
}
|
|
|
|
func (ctx *Context) newDependencyProviderResourceFromRef(ref string) ProviderResource {
|
|
idx := strings.LastIndex(ref, "::")
|
|
if idx == -1 {
|
|
return nil
|
|
}
|
|
urn, id := ref[:idx], ref[idx+2:]
|
|
return ctx.newDependencyProviderResource(URN(urn), ID(id))
|
|
}
|
|
|
|
// Resource represents a cloud resource managed by Pulumi.
|
|
type Resource interface {
|
|
internal.Resource
|
|
|
|
// URN is this resource's stable logical URN used to distinctly address it before, during, and after deployments.
|
|
URN() URNOutput
|
|
|
|
// getChildren returns the resource's children.
|
|
getChildren() []Resource
|
|
|
|
// addChild adds a child to the resource.
|
|
addChild(r Resource)
|
|
|
|
// getProviders returns the provider map for this resource.
|
|
getProviders() map[string]ProviderResource
|
|
|
|
// getProvider returns the provider for the resource.
|
|
getProvider() ProviderResource
|
|
|
|
// getVersion returns the version for the resource.
|
|
getVersion() string
|
|
|
|
// getPluginDownloadURL returns the provider plugin download url
|
|
getPluginDownloadURL() string
|
|
|
|
// getAliases returns the list of aliases for this resource
|
|
getAliases() []URNOutput
|
|
|
|
// getName returns the name of the resource
|
|
getName() string
|
|
|
|
// getTransformations returns the transformations for the resource.
|
|
getTransformations() []ResourceTransformation
|
|
|
|
// addTransformation adds a single transformation to the resource.
|
|
addTransformation(t ResourceTransformation)
|
|
|
|
// setKeepDependency marks this resource as a resource that should be kept as a dependency.
|
|
// This is done for remote component resources, dependency resources, and rehydrated component resources.
|
|
setKeepDependency()
|
|
|
|
// keepDependency returns true if the resource should be kept as a dependency, which is the case for
|
|
// remote component resources, dependency resources, and rehydrated component resources.
|
|
keepDependency() bool
|
|
}
|
|
|
|
var _ internal.Resource = (Resource)(nil)
|
|
|
|
// CustomResource is a cloud resource whose create, read, update, and delete (CRUD) operations are managed by performing
|
|
// external operations on some physical entity. The engine understands how to diff and perform partial updates of them,
|
|
// and these CRUD operations are implemented in a dynamically loaded plugin for the defining package.
|
|
type CustomResource interface {
|
|
Resource
|
|
// ID is the provider-assigned unique identifier for this managed resource. It is set during deployments,
|
|
// but might be missing ("") during planning phases.
|
|
ID() IDOutput
|
|
|
|
isCustomResource()
|
|
}
|
|
|
|
// ComponentResource is a resource that aggregates one or more other child resources into a higher level abstraction.
|
|
// The component resource itself is a resource, but does not require custom CRUD operations for provisioning.
|
|
type ComponentResource interface {
|
|
Resource
|
|
}
|
|
|
|
// ProviderResource is a resource that represents a configured instance of a particular package's provider plugin.
|
|
// These resources are supply the implementations of their package's CRUD operations. A specific provider instance can
|
|
// be used for a given resource by passing it in ResourceOpt.Provider.
|
|
type ProviderResource interface {
|
|
CustomResource
|
|
|
|
getPackage() string
|
|
}
|
|
|
|
// CustomTimeouts specifies timeouts for resource provisioning operations.
|
|
// Use it with the [Timeouts] option when creating new resources
|
|
// to override default timeouts.
|
|
//
|
|
// Each timeout is specified as a duration string such as,
|
|
// "5ms" (5 milliseconds), "40s" (40 seconds),
|
|
// and "1m30s" (1 minute, 30 seconds).
|
|
//
|
|
// The following units are accepted.
|
|
//
|
|
// - ns: nanoseconds
|
|
// - us: microseconds
|
|
// - µs: microseconds
|
|
// - ms: milliseconds
|
|
// - s: seconds
|
|
// - m: minutes
|
|
// - h: hours
|
|
type CustomTimeouts struct {
|
|
Create string
|
|
Update string
|
|
Delete string
|
|
}
|
|
|
|
// ResourceOptions is a snapshot of one or more [ResourceOption]s.
|
|
//
|
|
// You cannot pass a ResourceOptions struct to a resource constructor.
|
|
// Instead, use individual [ResourceOption] values to configure a resource.
|
|
// The ResourceOptions struct only provides a read-only preview
|
|
// of the collective effect of the options.
|
|
//
|
|
// See https://www.pulumi.com/docs/intro/concepts/resources/options/
|
|
// for more details on individual options.
|
|
type ResourceOptions struct {
|
|
// AdditionalSecretOutputs lists output properties
|
|
// that must be encrypted as secrets.
|
|
AdditionalSecretOutputs []string
|
|
|
|
// Aliases lists aliases for this resource
|
|
// that are used to find and use existing resources.
|
|
Aliases []Alias
|
|
|
|
// CustomTimeouts, if set, overrides the default timeouts
|
|
// for resource CRUD operations.
|
|
CustomTimeouts *CustomTimeouts
|
|
|
|
// DeleteBeforeReplace specifies that resources being replaced
|
|
// should be deleted before creating the replacement
|
|
// instead of Pulumi's default behavior of creating the replacement
|
|
// before performing deletion.
|
|
DeleteBeforeReplace bool
|
|
|
|
// DependsOn lists additional explicit dependencies for the resource
|
|
// in addition to those tracked automatically by Pulumi.
|
|
DependsOn []Resource
|
|
|
|
// DependsOnInputs holds explicit dependencies for the resource
|
|
// that may not be fully known yet.
|
|
DependsOnInputs []ResourceArrayInput
|
|
|
|
// IgnoreChanges lists properties changes to which should be ignored.
|
|
IgnoreChanges []string
|
|
|
|
// Import specifies that the provider for this resource
|
|
// should import its state from a cloud resource with the given ID.
|
|
Import IDInput
|
|
|
|
// Parent is the parent resource for the resource being created,
|
|
// or nil if this resource does not have a parent.
|
|
Parent Resource
|
|
|
|
// Protect prevents this resource from being deleted.
|
|
Protect bool
|
|
|
|
// Provider is the provider resource to use for this resource's CRUD operations.
|
|
// It's nil if the default provider should be used.
|
|
Provider ProviderResource
|
|
|
|
// Providers is a bag of providers available
|
|
// to instantiate resources of various types.
|
|
// These are used for a type when a provider for that type
|
|
// was not explicitly supplied.
|
|
Providers []ProviderResource
|
|
|
|
// ReplaceOnChanges lists properties that, when modified,
|
|
// force a replacement of the resource.
|
|
// The list may include '*' to indicate that all properties trigger
|
|
// replacements.
|
|
ReplaceOnChanges []string
|
|
|
|
// Transformations is a list of functions that transform
|
|
// the resource's properties during construction.
|
|
Transformations []ResourceTransformation
|
|
|
|
// Transforms is a list of functions that transform
|
|
// the resource's properties during construction.
|
|
//
|
|
// Experimental.
|
|
Transforms []XResourceTransform
|
|
|
|
// URN is the URN of a previously-registered resource of this type.
|
|
URN string
|
|
|
|
// Version changes the version of the provider plugin that should be used
|
|
// when operating on this resource.
|
|
// This will be blank if the version was automatically inferred.
|
|
Version string
|
|
|
|
// PluginDownloadURL specifies the URL from which the provider plugin
|
|
// should be downloaded.
|
|
// This will be blank if the URL was inferred automatically.
|
|
PluginDownloadURL string
|
|
|
|
// RetainOnDelete specifies that the resource should not be deleted
|
|
// in the cloud provider, even if it's deleted from Pulumi.
|
|
RetainOnDelete bool
|
|
|
|
// DeletedWith holds a container resource that, if deleted,
|
|
// also deletes this resource.
|
|
DeletedWith Resource
|
|
}
|
|
|
|
// NewResourceOptions builds a preview of the effect of the provided options.
|
|
//
|
|
// Use this to get a read-only snapshot of a list of options
|
|
// inside mocks and component resources.
|
|
func NewResourceOptions(opts ...ResourceOption) (*ResourceOptions, error) {
|
|
// The error return is currently unused,
|
|
// but it's foreseeable that we'll need it
|
|
// if we begin doing option validation at option merge time.
|
|
return resourceOptionsSnapshot(merge(opts...)), nil
|
|
}
|
|
|
|
// resourceOptions is the internal representation of the effect of
|
|
// [ResourceOption]s.
|
|
type resourceOptions struct {
|
|
AdditionalSecretOutputs []string
|
|
Aliases []Alias
|
|
CustomTimeouts *CustomTimeouts
|
|
DeleteBeforeReplace bool
|
|
DependsOn []dependencySet
|
|
IgnoreChanges []string
|
|
Import IDInput
|
|
Parent Resource
|
|
Protect bool
|
|
Provider ProviderResource
|
|
Providers map[string]ProviderResource
|
|
ReplaceOnChanges []string
|
|
Transformations []ResourceTransformation
|
|
Transforms []XResourceTransform
|
|
URN string
|
|
Version string
|
|
PluginDownloadURL string
|
|
RetainOnDelete bool
|
|
DeletedWith Resource
|
|
}
|
|
|
|
func resourceOptionsSnapshot(ro *resourceOptions) *ResourceOptions {
|
|
var (
|
|
dependsOn []Resource
|
|
dependsOnInputs []ResourceArrayInput
|
|
)
|
|
for _, d := range ro.DependsOn {
|
|
switch d := d.(type) {
|
|
case resourceDependencySet:
|
|
dependsOn = append(dependsOn, []Resource(d)...)
|
|
case *resourceArrayInputDependencySet:
|
|
dependsOnInputs = append(dependsOnInputs, d.input)
|
|
default:
|
|
// Unreachable.
|
|
// We control all implementations of dependencySet.
|
|
contract.Failf("Unknown dependencySet %T", d)
|
|
}
|
|
}
|
|
|
|
sort.Slice(dependsOn, func(i, j int) bool {
|
|
return dependsOn[i].getName() < dependsOn[j].getName()
|
|
})
|
|
|
|
var providers []ProviderResource
|
|
if len(ro.Providers) > 0 {
|
|
providers = slice.Prealloc[ProviderResource](len(ro.Providers))
|
|
for _, p := range ro.Providers {
|
|
providers = append(providers, p)
|
|
}
|
|
sort.Slice(providers, func(i, j int) bool {
|
|
return providers[i].getPackage() < providers[j].getPackage()
|
|
})
|
|
}
|
|
|
|
return &ResourceOptions{
|
|
AdditionalSecretOutputs: ro.AdditionalSecretOutputs,
|
|
Aliases: ro.Aliases,
|
|
CustomTimeouts: ro.CustomTimeouts,
|
|
DeleteBeforeReplace: ro.DeleteBeforeReplace,
|
|
DependsOn: dependsOn,
|
|
DependsOnInputs: dependsOnInputs,
|
|
IgnoreChanges: ro.IgnoreChanges,
|
|
Import: ro.Import,
|
|
Parent: ro.Parent,
|
|
Protect: ro.Protect,
|
|
Provider: ro.Provider,
|
|
Providers: providers,
|
|
ReplaceOnChanges: ro.ReplaceOnChanges,
|
|
Transformations: ro.Transformations,
|
|
Transforms: ro.Transforms,
|
|
URN: ro.URN,
|
|
Version: ro.Version,
|
|
PluginDownloadURL: ro.PluginDownloadURL,
|
|
RetainOnDelete: ro.RetainOnDelete,
|
|
DeletedWith: ro.DeletedWith,
|
|
}
|
|
}
|
|
|
|
// InvokeOptions is a snapshot of one or more [InvokeOption]s.
|
|
//
|
|
// You cannot pass an InvokeOptions struct to a provider function.
|
|
// Instead, use individual [InvokeOption] values to configure a call.
|
|
// The InvokeOptions struct only provides a read-only preview
|
|
// of the collective effect of the options.
|
|
type InvokeOptions struct {
|
|
// Parent is the parent resource for this operation.
|
|
// It may be used to determine the provider to use.
|
|
Parent Resource
|
|
// Provider specifies the provider to use for this operation.
|
|
// This is nil if the default provider should be used.
|
|
Provider ProviderResource
|
|
// Version is the version of the provider plugin that should be used.
|
|
// This will be blank if the version was automatically inferred.
|
|
Version string
|
|
// PluginDownloadURL is the URL from which the provider plugin
|
|
// should be downloaded.
|
|
// This will be blank if the URL was inferred automatically.
|
|
PluginDownloadURL string
|
|
}
|
|
|
|
// NOTE:
|
|
// InvokeOptions is part of the public API.
|
|
// If you introduce a new option,
|
|
// consider what its "snapshot" should look like,
|
|
// not the internal representation.
|
|
// For example, a list of resources should be []Resource,
|
|
// even if it's stored as a map[string]Resource.
|
|
// If the snapshot representation diverges from the internal,
|
|
// mirror this struct into a private invokeOptions struct.
|
|
// See resourceOptions for an example.
|
|
|
|
// NewInvokeOptions builds a preview of the effect of the provided options.
|
|
//
|
|
// Use this to get a read-only snapshot of the collective effect
|
|
// of a list of [InvokeOption]s.
|
|
func NewInvokeOptions(opts ...InvokeOption) (*InvokeOptions, error) {
|
|
var options InvokeOptions
|
|
for _, o := range opts {
|
|
if o != nil {
|
|
o.applyInvokeOption(&options)
|
|
}
|
|
}
|
|
// The error return is currently unused,
|
|
// but it's foreseeable that we'll need it
|
|
// if we begin doing option validation at option merge time.
|
|
return &options, nil
|
|
}
|
|
|
|
type ResourceOption interface {
|
|
applyResourceOption(*resourceOptions)
|
|
}
|
|
|
|
type InvokeOption interface {
|
|
applyInvokeOption(*InvokeOptions)
|
|
}
|
|
|
|
type ResourceOrInvokeOption interface {
|
|
ResourceOption
|
|
InvokeOption
|
|
}
|
|
|
|
type resourceOption func(*resourceOptions)
|
|
|
|
func (o resourceOption) applyResourceOption(opts *resourceOptions) {
|
|
o(opts)
|
|
}
|
|
|
|
type invokeOption func(*InvokeOptions)
|
|
|
|
func (o invokeOption) applyInvokeOption(opts *InvokeOptions) {
|
|
o(opts)
|
|
}
|
|
|
|
type resourceOrInvokeOption func(ro *resourceOptions, io *InvokeOptions)
|
|
|
|
func (o resourceOrInvokeOption) applyResourceOption(opts *resourceOptions) {
|
|
o(opts, nil)
|
|
}
|
|
|
|
func (o resourceOrInvokeOption) applyInvokeOption(opts *InvokeOptions) {
|
|
o(nil, opts)
|
|
}
|
|
|
|
// merging is handled by each functional options call
|
|
// properties that are arrays/maps are always appended/merged together
|
|
// last value wins for non-array/map values and for conflicting map values (bool, struct, etc)
|
|
func merge(opts ...ResourceOption) *resourceOptions {
|
|
options := &resourceOptions{}
|
|
for _, o := range opts {
|
|
if o != nil {
|
|
o.applyResourceOption(options)
|
|
}
|
|
}
|
|
return options
|
|
}
|
|
|
|
// AdditionalSecretOutputs specifies a list of output properties to mark as secret.
|
|
func AdditionalSecretOutputs(o []string) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.AdditionalSecretOutputs = append(ro.AdditionalSecretOutputs, o...)
|
|
})
|
|
}
|
|
|
|
// Aliases applies a list of identifiers to find and use existing resources.
|
|
func Aliases(o []Alias) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.Aliases = append(ro.Aliases, o...)
|
|
})
|
|
}
|
|
|
|
// DeleteBeforeReplace, when set to true, ensures that this resource is deleted prior to replacement.
|
|
func DeleteBeforeReplace(o bool) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.DeleteBeforeReplace = o
|
|
})
|
|
}
|
|
|
|
// Composite is a resource option that contains other resource options.
|
|
func Composite(opts ...ResourceOption) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
for _, o := range opts {
|
|
o.applyResourceOption(ro)
|
|
}
|
|
})
|
|
}
|
|
|
|
// CompositeInvoke is an invoke option that contains other invoke options.
|
|
func CompositeInvoke(opts ...InvokeOption) InvokeOption {
|
|
return invokeOption(func(ro *InvokeOptions) {
|
|
for _, o := range opts {
|
|
o.applyInvokeOption(ro)
|
|
}
|
|
})
|
|
}
|
|
|
|
// dependencySet unifies types that can provide dependencies for a
|
|
// resource.
|
|
type dependencySet interface {
|
|
// Adds URNs for addURNs from this set
|
|
// into the given urnSet.
|
|
// Optionally pass the last Resource arg to short-circuit component
|
|
// children cycles.
|
|
addURNs(context.Context, urnSet, Resource) error
|
|
}
|
|
|
|
// DependsOn is an optional array of explicit dependencies on other resources.
|
|
func DependsOn(o []Resource) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.DependsOn = append(ro.DependsOn, resourceDependencySet(o))
|
|
})
|
|
}
|
|
|
|
// resourceDependencySet is a dependencySet comprised of references to
|
|
// resources.
|
|
type resourceDependencySet []Resource
|
|
|
|
var _ dependencySet = (resourceDependencySet)(nil)
|
|
|
|
func (rs resourceDependencySet) addURNs(ctx context.Context, urns urnSet, from Resource) error {
|
|
for _, r := range rs {
|
|
if err := addDependency(ctx, urns, r, from); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Declares explicit dependencies on other resources. Similar to
|
|
// `DependsOn`, but also admits resource inputs and outputs:
|
|
//
|
|
// var r Resource
|
|
// var ri ResourceInput
|
|
// var ro ResourceOutput
|
|
// allDeps := NewResourceArrayOutput(NewResourceOutput(r), ri.ToResourceOutput(), ro)
|
|
// DependsOnInputs(allDeps)
|
|
func DependsOnInputs(o ResourceArrayInput) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.DependsOn = append(ro.DependsOn, &resourceArrayInputDependencySet{o})
|
|
})
|
|
}
|
|
|
|
// resourceArrayInputDependencySet is a dependencySet built from
|
|
// collections of resources that are not yet known.
|
|
type resourceArrayInputDependencySet struct{ input ResourceArrayInput }
|
|
|
|
var _ dependencySet = (*resourceArrayInputDependencySet)(nil)
|
|
|
|
func (ra *resourceArrayInputDependencySet) addURNs(ctx context.Context, urns urnSet, from Resource) error {
|
|
out := ra.input.ToResourceArrayOutput()
|
|
|
|
value, known, _ /* secret */, _ /* deps */, err := internal.AwaitOutput(ctx, out)
|
|
if err != nil || !known {
|
|
return err
|
|
}
|
|
|
|
resources, ok := value.([]Resource)
|
|
if !ok {
|
|
return fmt.Errorf("ResourceArrayInput resolved to a value of unexpected type %v, expected []Resource",
|
|
reflect.TypeOf(value))
|
|
}
|
|
|
|
// For some reason, deps returned above are incorrect; instead:
|
|
toplevelDeps := getOutputDeps(out)
|
|
|
|
for _, r := range append(resources, toplevelDeps...) {
|
|
if err := addDependency(ctx, urns, r, from); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Ignore changes to any of the specified properties.
|
|
func IgnoreChanges(o []string) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.IgnoreChanges = append(ro.IgnoreChanges, o...)
|
|
})
|
|
}
|
|
|
|
// Import, when provided with a resource ID, indicates that this resource's provider should import its state from
|
|
// the cloud resource with the given ID. The inputs to the resource's constructor must align with the resource's
|
|
// current state. Once a resource has been imported, the import property must be removed from the resource's
|
|
// options.
|
|
func Import(o IDInput) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.Import = o
|
|
})
|
|
}
|
|
|
|
// Parent sets the parent resource to which this resource or invoke belongs.
|
|
func Parent(r Resource) ResourceOrInvokeOption {
|
|
return resourceOrInvokeOption(func(ro *resourceOptions, io *InvokeOptions) {
|
|
switch {
|
|
case ro != nil:
|
|
ro.Parent = r
|
|
case io != nil:
|
|
io.Parent = r
|
|
}
|
|
})
|
|
}
|
|
|
|
// Protect, when set to true, ensures that this resource cannot be deleted (without first setting it to false).
|
|
func Protect(o bool) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.Protect = o
|
|
})
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// NOTE(Provider and Providers)
|
|
//
|
|
// For Provider vs Providers, there's a bit of complexity.
|
|
//
|
|
// # Background
|
|
//
|
|
// First, here's the desired behavior across languages,
|
|
// as standardized in #8796:
|
|
//
|
|
// - Providers is a bag of providers available to a resource.
|
|
// These are used by the resource and its children.
|
|
// - Provider passed to a resource indicates that that specific resource
|
|
// MUST use this provider over all else,
|
|
// and it should add it to the bag of providers for use by its children.
|
|
//
|
|
// One discrepancy from the above is that originally, for the Provider option,
|
|
// mismatch between the provider package and resource type was an error.
|
|
// However, this appears to have been relaxed over time.
|
|
// In such a case, the provider is added to the bag of providers
|
|
// and used by the children of the resource.
|
|
// This is necessary, for example, for resources to inherit a provider
|
|
// passed to a component resource via the Provider option.
|
|
//
|
|
// # Go-specific difference
|
|
//
|
|
// In other languages, the Provider and Providers options can be provided at
|
|
// most once per resource.
|
|
// In Go, because we use functional options, we allow multiple calls to
|
|
// the Provider and Providers options.
|
|
// This has allowed for the following to be equivalen in Go:
|
|
//
|
|
// NewFoo(..., Provider(p1), Provider(p2), Provider(p3))
|
|
// NewFoo(..., Providers(p1, p2, p3))
|
|
//
|
|
// To support this while still having the Provider option take precedence,
|
|
// we need to do the following:
|
|
//
|
|
// 1. All providers (whether passed with Provider or Providers)
|
|
// are merged into a single map.
|
|
// Last provider for a given package wins.
|
|
// 2. For the Provider option, we additionally track the last
|
|
// passed value in a separate field.
|
|
// If this provider handles the current resource,
|
|
// it takes precedence over the map.
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Provider sets the provider resource to use for a resource's CRUD operations or an invoke's call.
|
|
func Provider(r ProviderResource) ResourceOrInvokeOption {
|
|
return resourceOrInvokeOption(func(ro *resourceOptions, io *InvokeOptions) {
|
|
switch {
|
|
case ro != nil:
|
|
ro.Provider = r
|
|
Providers(r).applyResourceOption(ro)
|
|
case io != nil:
|
|
io.Provider = r
|
|
}
|
|
})
|
|
}
|
|
|
|
// ProviderMap is an optional map of package to provider resource for a component resource.
|
|
func ProviderMap(o map[string]ProviderResource) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
if o != nil {
|
|
if ro.Providers == nil {
|
|
ro.Providers = make(map[string]ProviderResource)
|
|
}
|
|
for k, v := range o {
|
|
ro.Providers[k] = v
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Providers is an optional list of providers to use for a resource's children.
|
|
func Providers(o ...ProviderResource) ResourceOption {
|
|
m := map[string]ProviderResource{}
|
|
for _, p := range o {
|
|
m[p.getPackage()] = p
|
|
}
|
|
return ProviderMap(m)
|
|
}
|
|
|
|
// ReplaceOnChanges will force a replacement when any of these property paths are set. If this list includes `"*"`,
|
|
// changes to any properties will force a replacement. Initialization errors from previous deployments will
|
|
// require replacement instead of update only if `"*"` is passed.
|
|
func ReplaceOnChanges(o []string) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.ReplaceOnChanges = append(ro.ReplaceOnChanges, o...)
|
|
})
|
|
}
|
|
|
|
// Timeouts is an optional configuration block used for CRUD operations
|
|
func Timeouts(o *CustomTimeouts) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.CustomTimeouts = o
|
|
})
|
|
}
|
|
|
|
// Transformations is an optional list of transformations to be applied to the resource.
|
|
func Transformations(o []ResourceTransformation) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.Transformations = append(ro.Transformations, o...)
|
|
})
|
|
}
|
|
|
|
// Transforms is an optional list of transforms to be applied to the resource.
|
|
//
|
|
// Experimental.
|
|
func Transforms(o []XResourceTransform) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.Transforms = append(ro.Transforms, o...)
|
|
})
|
|
}
|
|
|
|
// URN_ is an optional URN of a previously-registered resource of this type to read from the engine.
|
|
//
|
|
//nolint:revive
|
|
func URN_(o string) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.URN = o
|
|
})
|
|
}
|
|
|
|
// Version is an optional version, corresponding to the version of the provider plugin that should be used when
|
|
// operating on this resource. This version overrides the version information inferred from the current package and
|
|
// should rarely be used.
|
|
func Version(o string) ResourceOrInvokeOption {
|
|
return resourceOrInvokeOption(func(ro *resourceOptions, io *InvokeOptions) {
|
|
switch {
|
|
case ro != nil:
|
|
ro.Version = o
|
|
case io != nil:
|
|
io.Version = o
|
|
}
|
|
})
|
|
}
|
|
|
|
// PluginDownloadURL is an optional url, corresponding to the download url of the provider plugin
|
|
// that should be used when operating on this resource. This url overrides the url information
|
|
// inferred from the current package and should rarely be used.
|
|
func PluginDownloadURL(o string) ResourceOrInvokeOption {
|
|
return resourceOrInvokeOption(func(ro *resourceOptions, io *InvokeOptions) {
|
|
switch {
|
|
case ro != nil:
|
|
ro.PluginDownloadURL = o
|
|
case io != nil:
|
|
io.PluginDownloadURL = o
|
|
}
|
|
})
|
|
}
|
|
|
|
// If set to True, the providers Delete method will not be called for this resource.
|
|
func RetainOnDelete(b bool) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.RetainOnDelete = b
|
|
})
|
|
}
|
|
|
|
// If set, the providers Delete method will not be called for this resource
|
|
// if specified resource is being deleted as well.
|
|
func DeletedWith(r Resource) ResourceOption {
|
|
return resourceOption(func(ro *resourceOptions) {
|
|
ro.DeletedWith = r
|
|
})
|
|
}
|