211 lines
9.4 KiB
Go
211 lines
9.4 KiB
Go
// Copyright 2016-2018, 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 plugin
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/pulumi/pulumi/sdk/go/common/resource"
|
|
"github.com/pulumi/pulumi/sdk/go/common/tokens"
|
|
"github.com/pulumi/pulumi/sdk/go/common/util/contract"
|
|
"github.com/pulumi/pulumi/sdk/go/common/workspace"
|
|
)
|
|
|
|
// Provider presents a simple interface for orchestrating resource create, read, update, and delete operations. Each
|
|
// provider understands how to handle all of the resource types within a single package.
|
|
//
|
|
// This interface hides some of the messiness of the underlying machinery, since providers are behind an RPC boundary.
|
|
//
|
|
// It is important to note that provider operations are not transactional. (Some providers might decide to offer
|
|
// transactional semantics, but such a provider is a rare treat.) As a result, failures in the operations below can
|
|
// range from benign to catastrophic (possibly leaving behind a corrupt resource). It is up to the provider to make a
|
|
// best effort to ensure catastrophes do not occur. The errors returned from mutating operations indicate both the
|
|
// underlying error condition in addition to a bit indicating whether the operation was successfully rolled back.
|
|
type Provider interface {
|
|
// Closer closes any underlying OS resources associated with this provider (like processes, RPC channels, etc).
|
|
io.Closer
|
|
// Pkg fetches this provider's package.
|
|
Pkg() tokens.Package
|
|
|
|
// GetSchema returns the schema for the provider.
|
|
GetSchema(version int) ([]byte, error)
|
|
|
|
// CheckConfig validates the configuration for this resource provider.
|
|
CheckConfig(urn resource.URN, olds, news resource.PropertyMap,
|
|
allowUnknowns bool) (resource.PropertyMap, []CheckFailure, error)
|
|
// DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider.
|
|
DiffConfig(urn resource.URN, olds, news resource.PropertyMap, allowUnknowns bool,
|
|
ignoreChanges []string) (DiffResult, error)
|
|
// Configure configures the resource provider with "globals" that control its behavior.
|
|
Configure(inputs resource.PropertyMap) error
|
|
|
|
// Check validates that the given property bag is valid for a resource of the given type and returns the inputs
|
|
// that should be passed to successive calls to Diff, Create, or Update for this resource.
|
|
Check(urn resource.URN, olds, news resource.PropertyMap,
|
|
allowUnknowns bool) (resource.PropertyMap, []CheckFailure, error)
|
|
// Diff checks what impacts a hypothetical update will have on the resource's properties.
|
|
Diff(urn resource.URN, id resource.ID, olds resource.PropertyMap, news resource.PropertyMap,
|
|
allowUnknowns bool, ignoreChanges []string) (DiffResult, error)
|
|
// Create allocates a new instance of the provided resource and returns its unique resource.ID.
|
|
Create(urn resource.URN, news resource.PropertyMap, timeout float64) (resource.ID, resource.PropertyMap,
|
|
resource.Status, error)
|
|
// Read the current live state associated with a resource. Enough state must be include in the inputs to uniquely
|
|
// identify the resource; this is typically just the resource ID, but may also include some properties. If the
|
|
// resource is missing (for instance, because it has been deleted), the resulting property map will be nil.
|
|
Read(urn resource.URN, id resource.ID,
|
|
inputs, state resource.PropertyMap) (ReadResult, resource.Status, error)
|
|
// Update updates an existing resource with new values.
|
|
Update(urn resource.URN, id resource.ID,
|
|
olds resource.PropertyMap, news resource.PropertyMap, timeout float64,
|
|
ignoreChanges []string) (resource.PropertyMap, resource.Status, error)
|
|
// Delete tears down an existing resource.
|
|
Delete(urn resource.URN, id resource.ID, props resource.PropertyMap, timeout float64) (resource.Status, error)
|
|
// Invoke dynamically executes a built-in function in the provider.
|
|
Invoke(tok tokens.ModuleMember, args resource.PropertyMap) (resource.PropertyMap, []CheckFailure, error)
|
|
// StreamInvoke dynamically executes a built-in function in the provider, which returns a stream
|
|
// of responses.
|
|
StreamInvoke(
|
|
tok tokens.ModuleMember,
|
|
args resource.PropertyMap,
|
|
onNext func(resource.PropertyMap) error) ([]CheckFailure, error)
|
|
// GetPluginInfo returns this plugin's information.
|
|
GetPluginInfo() (workspace.PluginInfo, error)
|
|
|
|
// SignalCancellation asks all resource providers to gracefully shut down and abort any ongoing
|
|
// operations. Operation aborted in this way will return an error (e.g., `Update` and `Create`
|
|
// will either a creation error or an initialization error. SignalCancellation is advisory and
|
|
// non-blocking; it is up to the host to decide how long to wait after SignalCancellation is
|
|
// called before (e.g.) hard-closing any gRPC connection.
|
|
SignalCancellation() error
|
|
}
|
|
|
|
// CheckFailure indicates that a call to check failed; it contains the property and reason for the failure.
|
|
type CheckFailure struct {
|
|
Property resource.PropertyKey // the property that failed checking.
|
|
Reason string // the reason the property failed to check.
|
|
}
|
|
|
|
// DiffChanges represents the kind of changes detected by a diff operation.
|
|
type DiffChanges int
|
|
|
|
const (
|
|
// DiffUnknown indicates the provider didn't offer information about the changes (legacy behavior).
|
|
DiffUnknown DiffChanges = 0
|
|
// DiffNone indicates the provider performed a diff and concluded that no update is needed.
|
|
DiffNone DiffChanges = 1
|
|
// DiffSome indicates the provider performed a diff and concluded that an update or replacement is needed.
|
|
DiffSome DiffChanges = 2
|
|
)
|
|
|
|
// DiffKind represents the kind of diff that applies to a particular property.
|
|
type DiffKind int
|
|
|
|
func (d DiffKind) String() string {
|
|
switch d {
|
|
case DiffAdd:
|
|
return "add"
|
|
case DiffAddReplace:
|
|
return "add-replace"
|
|
case DiffDelete:
|
|
return "delete"
|
|
case DiffDeleteReplace:
|
|
return "delete-replace"
|
|
case DiffUpdate:
|
|
return "update"
|
|
case DiffUpdateReplace:
|
|
return "update-replace"
|
|
default:
|
|
contract.Failf("Unknown diff kind %v", int(d))
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func (d DiffKind) IsReplace() bool {
|
|
switch d {
|
|
case DiffAddReplace, DiffDeleteReplace, DiffUpdateReplace:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
const (
|
|
// DiffAdd indicates that the property was added.
|
|
DiffAdd DiffKind = 0
|
|
// DiffAddReplace indicates that the property was added and requires that the resource be replaced.
|
|
DiffAddReplace DiffKind = 1
|
|
// DiffDelete indicates that the property was deleted.
|
|
DiffDelete DiffKind = 2
|
|
// DiffDeleteReplace indicates that the property was added and requires that the resource be replaced.
|
|
DiffDeleteReplace DiffKind = 3
|
|
// DiffUpdate indicates that the property was updated.
|
|
DiffUpdate DiffKind = 4
|
|
// DiffUpdateReplace indicates that the property was updated and requires that the resource be replaced.
|
|
DiffUpdateReplace DiffKind = 5
|
|
)
|
|
|
|
// PropertyDiff records the difference between a single property's old and new values.
|
|
type PropertyDiff struct {
|
|
Kind DiffKind // The kind of diff.
|
|
InputDiff bool // True if this is a diff between old and new inputs rather than old state and new inputs.
|
|
}
|
|
|
|
// DiffResult indicates whether an operation should replace or update an existing resource.
|
|
type DiffResult struct {
|
|
Changes DiffChanges // true if this diff represents a changed resource.
|
|
ReplaceKeys []resource.PropertyKey // an optional list of replacement keys.
|
|
StableKeys []resource.PropertyKey // an optional list of property keys that are stable.
|
|
ChangedKeys []resource.PropertyKey // an optional list of keys that changed.
|
|
DetailedDiff map[string]PropertyDiff // an optional structured diff
|
|
DeleteBeforeReplace bool // if true, this resource must be deleted before recreating it.
|
|
}
|
|
|
|
// Replace returns true if this diff represents a replacement.
|
|
func (r DiffResult) Replace() bool {
|
|
for _, v := range r.DetailedDiff {
|
|
if v.Kind.IsReplace() {
|
|
return true
|
|
}
|
|
}
|
|
return len(r.ReplaceKeys) > 0
|
|
}
|
|
|
|
// DiffUnavailableError may be returned by a provider if the provider is unable to diff a resource.
|
|
type DiffUnavailableError struct {
|
|
reason string
|
|
}
|
|
|
|
// DiffUnavailable creates a new DiffUnavailableError with the given message.
|
|
func DiffUnavailable(reason string) DiffUnavailableError {
|
|
return DiffUnavailableError{reason: reason}
|
|
}
|
|
|
|
// Error returns the error message for this DiffUnavailableError.
|
|
func (e DiffUnavailableError) Error() string {
|
|
return e.reason
|
|
}
|
|
|
|
// ReadResult is the result of a call to Read.
|
|
type ReadResult struct {
|
|
// This is the ID for the resource. This ID will always be populated and will ensure we get the most up-to-date
|
|
// resource ID.
|
|
ID resource.ID
|
|
// Inputs contains the new inputs for the resource, if any. If this field is nil, the provider does not support
|
|
// returning inputs from a call to Read and the old inputs (if any) should be preserved.
|
|
Inputs resource.PropertyMap
|
|
// Outputs contains the new outputs/state for the resource, if any. If this field is nil, the resource does not
|
|
// exist.
|
|
Outputs resource.PropertyMap
|
|
}
|