Implement get
functions on all resources
This change implements the `get` function for resources. Per pulumi/lumi#83, this allows Lumi scripts to actually read from the target environment. For example, we can now look up a SecurityGroup from its ARN: let group = aws.ec2.SecurityGroup.get( "arn:aws:ec2:us-west-2:153052954103:security-group:sg-02150d79"); The returned object is a fully functional resource object. So, we can then link it up with an EC2 instance, for example, in the usual ways: let instance = new aws.ec2.Instance(..., { securityGroups: [ group ], }); This didn't require any changes to the RPC or provider model, since we already implement the Get function. There are a few loose ends; two are short term: 1) URNs are not rehydrated. 2) Query is not yet implemented. One is mid-term: 3) We probably want a URN-based lookup function. But we will likely wait until we tackle pulumi/lumi#109 before adding this. And one is long term (and subtle): 4) These amount to I/O and are not repeatable! A change in the target environment may cause a script to generate a different plan intermittently. Most likely we want to apply a different kind of deployment "policy" for such scripts. These are inching towards the scripting model of pulumi/lumi#121, which is an entirely different beast than the repeatable immutable infrastructure deployments. Finally, it is worth noting that with this, we have some of the fundamental underpinnings required to finally tackle "inference" (pulumi/lumi#142).
This commit is contained in:
parent
c265620f28
commit
26cf93f759
|
@ -37,7 +37,8 @@ func newDeployCmd() *cobra.Command {
|
||||||
var dryRun bool
|
var dryRun bool
|
||||||
var env string
|
var env string
|
||||||
var showConfig bool
|
var showConfig bool
|
||||||
var showReplaceSteps bool
|
var showReads bool
|
||||||
|
var showReplaceDeletes bool
|
||||||
var showSames bool
|
var showSames bool
|
||||||
var summary bool
|
var summary bool
|
||||||
var output string
|
var output string
|
||||||
|
@ -62,14 +63,15 @@ func newDeployCmd() *cobra.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
deployLatest(cmd, info, deployOptions{
|
deployLatest(cmd, info, deployOptions{
|
||||||
Delete: false,
|
Delete: false,
|
||||||
DryRun: dryRun,
|
DryRun: dryRun,
|
||||||
Analyzers: analyzers,
|
Analyzers: analyzers,
|
||||||
ShowConfig: showConfig,
|
ShowConfig: showConfig,
|
||||||
ShowReplaceSteps: showReplaceSteps,
|
ShowReads: showReads,
|
||||||
ShowSames: showSames,
|
ShowReplaceDeletes: showReplaceDeletes,
|
||||||
Summary: summary,
|
ShowSames: showSames,
|
||||||
Output: output,
|
Summary: summary,
|
||||||
|
Output: output,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}),
|
}),
|
||||||
|
@ -88,7 +90,10 @@ func newDeployCmd() *cobra.Command {
|
||||||
&showConfig, "show-config", false,
|
&showConfig, "show-config", false,
|
||||||
"Show configuration keys and variables")
|
"Show configuration keys and variables")
|
||||||
cmd.PersistentFlags().BoolVar(
|
cmd.PersistentFlags().BoolVar(
|
||||||
&showReplaceSteps, "show-replace-steps", false,
|
&showReads, "show-reads", false,
|
||||||
|
"Show resources that will be read, in addition to those that will be modified")
|
||||||
|
cmd.PersistentFlags().BoolVar(
|
||||||
|
&showReplaceDeletes, "show-replace-deletes", false,
|
||||||
"Show detailed resource replacement creates and deletes; normally shows as a single step")
|
"Show detailed resource replacement creates and deletes; normally shows as a single step")
|
||||||
cmd.PersistentFlags().BoolVar(
|
cmd.PersistentFlags().BoolVar(
|
||||||
&showSames, "show-sames", false,
|
&showSames, "show-sames", false,
|
||||||
|
@ -104,16 +109,17 @@ func newDeployCmd() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
type deployOptions struct {
|
type deployOptions struct {
|
||||||
Create bool // true if we are creating resources.
|
Create bool // true if we are creating resources.
|
||||||
Delete bool // true if we are deleting resources.
|
Delete bool // true if we are deleting resources.
|
||||||
DryRun bool // true if we should just print the plan without performing it.
|
DryRun bool // true if we should just print the plan without performing it.
|
||||||
Analyzers []string // an optional set of analyzers to run as part of this deployment.
|
Analyzers []string // an optional set of analyzers to run as part of this deployment.
|
||||||
ShowConfig bool // true to show the configuration variables being used.
|
ShowConfig bool // true to show the configuration variables being used.
|
||||||
ShowReplaceSteps bool // true to show the replacement steps in the plan.
|
ShowReads bool // true to show the read-only steps in the plan.
|
||||||
ShowSames bool // true to show the resources that aren't updated, in addition to those that are.
|
ShowReplaceDeletes bool // true to show the replacement deletion steps in the plan.
|
||||||
Summary bool // true if we should only summarize resources and operations.
|
ShowSames bool // true to show the resources that aren't updated, in addition to those that are.
|
||||||
DOT bool // true if we should print the DOT file for this plan.
|
Summary bool // true if we should only summarize resources and operations.
|
||||||
Output string // the place to store the output, if any.
|
DOT bool // true if we should print the DOT file for this plan.
|
||||||
|
Output string // the place to store the output, if any.
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployLatest(cmd *cobra.Command, info *envCmdInfo, opts deployOptions) error {
|
func deployLatest(cmd *cobra.Command, info *envCmdInfo, opts deployOptions) error {
|
||||||
|
@ -132,7 +138,7 @@ func deployLatest(cmd *cobra.Command, info *envCmdInfo, opts deployOptions) erro
|
||||||
|
|
||||||
// Create an object to track progress and perform the actual operations.
|
// Create an object to track progress and perform the actual operations.
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
progress := newProgress(opts.Summary)
|
progress := newProgress(opts)
|
||||||
summary, _, _, err := result.Plan.Apply(progress)
|
summary, _, _, err := result.Plan.Apply(progress)
|
||||||
contract.Assert(summary != nil)
|
contract.Assert(summary != nil)
|
||||||
empty := (summary.Steps() == 0) // if no step is returned, it was empty.
|
empty := (summary.Steps() == 0) // if no step is returned, it was empty.
|
||||||
|
@ -143,7 +149,7 @@ func deployLatest(cmd *cobra.Command, info *envCmdInfo, opts deployOptions) erro
|
||||||
cmdutil.Diag().Infof(diag.Message("no resources need to be updated"))
|
cmdutil.Diag().Infof(diag.Message("no resources need to be updated"))
|
||||||
} else {
|
} else {
|
||||||
// Print out the total number of steps performed (and their kinds), the duration, and any summary info.
|
// Print out the total number of steps performed (and their kinds), the duration, and any summary info.
|
||||||
printSummary(&footer, progress.Ops, opts.ShowReplaceSteps, false)
|
printSummary(&footer, progress.Ops, false)
|
||||||
footer.WriteString(fmt.Sprintf("%vDeployment duration: %v%v\n",
|
footer.WriteString(fmt.Sprintf("%vDeployment duration: %v%v\n",
|
||||||
colors.SpecUnimportant, time.Since(start), colors.Reset))
|
colors.SpecUnimportant, time.Since(start), colors.Reset))
|
||||||
}
|
}
|
||||||
|
@ -171,18 +177,18 @@ type deployProgress struct {
|
||||||
Steps int
|
Steps int
|
||||||
Ops map[deploy.StepOp]int
|
Ops map[deploy.StepOp]int
|
||||||
MaybeCorrupt bool
|
MaybeCorrupt bool
|
||||||
Summary bool
|
Opts deployOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProgress(summary bool) *deployProgress {
|
func newProgress(opts deployOptions) *deployProgress {
|
||||||
return &deployProgress{
|
return &deployProgress{
|
||||||
Steps: 0,
|
Steps: 0,
|
||||||
Ops: make(map[deploy.StepOp]int),
|
Ops: make(map[deploy.StepOp]int),
|
||||||
Summary: summary,
|
Opts: opts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (prog *deployProgress) Before(step *deploy.Step) {
|
func (prog *deployProgress) Before(step deploy.Step) {
|
||||||
stepop := step.Op()
|
stepop := step.Op()
|
||||||
if stepop == deploy.OpSame {
|
if stepop == deploy.OpSame {
|
||||||
return
|
return
|
||||||
|
@ -192,17 +198,18 @@ func (prog *deployProgress) Before(step *deploy.Step) {
|
||||||
stepnum := prog.Steps + 1
|
stepnum := prog.Steps + 1
|
||||||
|
|
||||||
var extra string
|
var extra string
|
||||||
if stepop == deploy.OpReplaceCreate || stepop == deploy.OpReplaceDelete {
|
if stepop == deploy.OpReplace ||
|
||||||
|
(stepop == deploy.OpDelete && step.(*deploy.DeleteStep).Replaced()) {
|
||||||
extra = " (part of a replacement change)"
|
extra = " (part of a replacement change)"
|
||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
b.WriteString(fmt.Sprintf("Applying step #%v [%v]%v\n", stepnum, stepop, extra))
|
b.WriteString(fmt.Sprintf("Applying step #%v [%v]%v\n", stepnum, stepop, extra))
|
||||||
printStep(&b, step, prog.Summary, false, "")
|
printStep(&b, step, prog.Opts.Summary, false, "")
|
||||||
fmt.Print(colors.Colorize(&b))
|
fmt.Print(colors.Colorize(&b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (prog *deployProgress) After(step *deploy.Step, status resource.Status, err error) {
|
func (prog *deployProgress) After(step deploy.Step, status resource.Status, err error) {
|
||||||
stepop := step.Op()
|
stepop := step.Op()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Issue a true, bonafide error.
|
// Issue a true, bonafide error.
|
||||||
|
@ -226,7 +233,7 @@ func (prog *deployProgress) After(step *deploy.Step, status resource.Status, err
|
||||||
b.WriteString(colors.Reset)
|
b.WriteString(colors.Reset)
|
||||||
b.WriteString("\n")
|
b.WriteString("\n")
|
||||||
fmt.Printf(colors.Colorize(&b))
|
fmt.Printf(colors.Colorize(&b))
|
||||||
} else if stepop != deploy.OpSame {
|
} else if shouldTrack(step, prog.Opts) {
|
||||||
// Increment the counters.
|
// Increment the counters.
|
||||||
prog.Steps++
|
prog.Steps++
|
||||||
prog.Ops[stepop]++
|
prog.Ops[stepop]++
|
||||||
|
|
156
cmd/lumi/plan.go
156
cmd/lumi/plan.go
|
@ -21,6 +21,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/pulumi/lumi/pkg/diag"
|
"github.com/pulumi/lumi/pkg/diag"
|
||||||
|
@ -38,7 +39,8 @@ func newPlanCmd() *cobra.Command {
|
||||||
var dotOutput bool
|
var dotOutput bool
|
||||||
var env string
|
var env string
|
||||||
var showConfig bool
|
var showConfig bool
|
||||||
var showReplaceSteps bool
|
var showReads bool
|
||||||
|
var showReplaceDeletes bool
|
||||||
var showSames bool
|
var showSames bool
|
||||||
var summary bool
|
var summary bool
|
||||||
var cmd = &cobra.Command{
|
var cmd = &cobra.Command{
|
||||||
|
@ -62,14 +64,15 @@ func newPlanCmd() *cobra.Command {
|
||||||
}
|
}
|
||||||
contract.Assertf(!dotOutput, "TODO[pulumi/lumi#235]: DOT files not yet supported")
|
contract.Assertf(!dotOutput, "TODO[pulumi/lumi#235]: DOT files not yet supported")
|
||||||
opts := deployOptions{
|
opts := deployOptions{
|
||||||
Delete: false,
|
Delete: false,
|
||||||
DryRun: true,
|
DryRun: true,
|
||||||
Analyzers: analyzers,
|
Analyzers: analyzers,
|
||||||
ShowConfig: showConfig,
|
ShowConfig: showConfig,
|
||||||
ShowReplaceSteps: showReplaceSteps,
|
ShowReads: showReads,
|
||||||
ShowSames: showSames,
|
ShowReplaceDeletes: showReplaceDeletes,
|
||||||
Summary: summary,
|
ShowSames: showSames,
|
||||||
DOT: dotOutput,
|
Summary: summary,
|
||||||
|
DOT: dotOutput,
|
||||||
}
|
}
|
||||||
if result := plan(cmd, info, opts); result != nil {
|
if result := plan(cmd, info, opts); result != nil {
|
||||||
if err := printPlan(result, opts); err != nil {
|
if err := printPlan(result, opts); err != nil {
|
||||||
|
@ -93,7 +96,10 @@ func newPlanCmd() *cobra.Command {
|
||||||
&showConfig, "show-config", false,
|
&showConfig, "show-config", false,
|
||||||
"Show configuration keys and variables")
|
"Show configuration keys and variables")
|
||||||
cmd.PersistentFlags().BoolVar(
|
cmd.PersistentFlags().BoolVar(
|
||||||
&showReplaceSteps, "show-replace-steps", false,
|
&showReads, "show-reads", false,
|
||||||
|
"Show resources that will be read, in addition to those that will be modified")
|
||||||
|
cmd.PersistentFlags().BoolVar(
|
||||||
|
&showReplaceDeletes, "show-replace-deletes", false,
|
||||||
"Show detailed resource replacement creates and deletes; normally shows as a single step")
|
"Show detailed resource replacement creates and deletes; normally shows as a single step")
|
||||||
cmd.PersistentFlags().BoolVar(
|
cmd.PersistentFlags().BoolVar(
|
||||||
&showSames, "show-sames", false,
|
&showSames, "show-sames", false,
|
||||||
|
@ -165,41 +171,44 @@ func printPlan(result *planResult, opts deployOptions) error {
|
||||||
|
|
||||||
iter, err := result.Plan.Iterate()
|
iter, err := result.Plan.Iterate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdutil.Diag().Errorf(diag.Message("An error occurred while preparing the plan: %v"), err)
|
return errors.Errorf("An error occurred while preparing the plan: %v", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
step, err := iter.Next()
|
step, err := iter.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdutil.Diag().Errorf(diag.Message("An error occurred while enumerating the plan: %v"), err)
|
return errors.Errorf("An error occurred while enumerating the plan: %v", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var summary bytes.Buffer
|
var summary bytes.Buffer
|
||||||
empty := true
|
empty := true
|
||||||
counts := make(map[deploy.StepOp]int)
|
counts := make(map[deploy.StepOp]int)
|
||||||
for step != nil {
|
for step != nil {
|
||||||
op := step.Op()
|
var err error
|
||||||
if empty && op != deploy.OpSame {
|
|
||||||
empty = false
|
// Perform the pre-step.
|
||||||
|
if err = step.Pre(); err != nil {
|
||||||
|
return errors.Errorf("An error occurred preparing the plan: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print this step information (resource and all its properties).
|
// Print this step information (resource and all its properties).
|
||||||
// IDEA: it would be nice if, in the output, we showed the dependencies a la `git log --graph`.
|
// IDEA: it would be nice if, in the output, we showed the dependencies a la `git log --graph`.
|
||||||
if (opts.ShowReplaceSteps || op != deploy.OpReplaceDelete) &&
|
track := shouldTrack(step, opts)
|
||||||
(opts.ShowSames || op != deploy.OpSame) {
|
if track {
|
||||||
printStep(&summary, step, opts.Summary, true, "")
|
printStep(&summary, step, opts.Summary, true, "")
|
||||||
|
empty = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Be sure to skip the step so that in-memory state updates are performed.
|
// Be sure to skip the step so that in-memory state updates are performed.
|
||||||
step.Skip()
|
if err = step.Skip(); err != nil {
|
||||||
|
return errors.Errorf("An error occurred while advancing the plan: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
counts[step.Op()]++
|
if track {
|
||||||
|
counts[step.Op()]++
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
|
||||||
if step, err = iter.Next(); err != nil {
|
if step, err = iter.Next(); err != nil {
|
||||||
cmdutil.Diag().Errorf(diag.Message("An error occurred while viewing the plan: %v"), err)
|
return errors.Errorf("An error occurred while viewing the plan: %v", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,12 +217,27 @@ func printPlan(result *planResult, opts deployOptions) error {
|
||||||
cmdutil.Diag().Infof(diag.Message("no resources need to be updated"))
|
cmdutil.Diag().Infof(diag.Message("no resources need to be updated"))
|
||||||
} else {
|
} else {
|
||||||
// Print a summary of operation counts.
|
// Print a summary of operation counts.
|
||||||
printSummary(&summary, counts, opts.ShowReplaceSteps, true)
|
printSummary(&summary, counts, true)
|
||||||
fmt.Print(colors.Colorize(&summary))
|
fmt.Print(colors.Colorize(&summary))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shouldTrack returns true if the step should be "tracked"; this affects two things: 1) whether the resource is shown
|
||||||
|
// in the planning phase and 2) whether the resource operation is tallied up and displayed in the final summary.
|
||||||
|
func shouldTrack(step deploy.Step, opts deployOptions) bool {
|
||||||
|
// For certain operations, whether they are tracked is controlled by flags (to cut down on superfluous output).
|
||||||
|
if _, isrd := step.(deploy.ReadStep); isrd {
|
||||||
|
return opts.ShowReads
|
||||||
|
} else if step.Op() == deploy.OpSame {
|
||||||
|
return opts.ShowSames
|
||||||
|
} else if step.Op() == deploy.OpDelete && step.(*deploy.DeleteStep).Replaced() {
|
||||||
|
return opts.ShowReplaceDeletes
|
||||||
|
}
|
||||||
|
// By default, however, steps are tracked.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func printPrelude(b *bytes.Buffer, result *planResult, opts deployOptions, planning bool) {
|
func printPrelude(b *bytes.Buffer, result *planResult, opts deployOptions, planning bool) {
|
||||||
// If there are configuration variables, show them.
|
// If there are configuration variables, show them.
|
||||||
if opts.ShowConfig {
|
if opts.ShowConfig {
|
||||||
|
@ -235,12 +259,9 @@ func printConfig(b *bytes.Buffer, config resource.ConfigMap) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printSummary(b *bytes.Buffer, counts map[deploy.StepOp]int, showReplaceSteps bool, plan bool) {
|
func printSummary(b *bytes.Buffer, counts map[deploy.StepOp]int, plan bool) {
|
||||||
total := 0
|
total := 0
|
||||||
for op, c := range counts {
|
for _, c := range counts {
|
||||||
if op == deploy.OpSame || (!showReplaceSteps && op == deploy.OpReplaceDelete) {
|
|
||||||
continue // skip counting replacement steps unless explicitly requested.
|
|
||||||
}
|
|
||||||
total += c
|
total += c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,10 +284,6 @@ func printSummary(b *bytes.Buffer, counts map[deploy.StepOp]int, showReplaceStep
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, op := range deploy.StepOps {
|
for _, op := range deploy.StepOps {
|
||||||
if op == deploy.OpSame || (!showReplaceSteps && op == deploy.OpReplaceDelete) {
|
|
||||||
// Unless the user requested it, don't show the fine-grained replacement steps; just the logical ones.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if c := counts[op]; c > 0 {
|
if c := counts[op]; c > 0 {
|
||||||
b.WriteString(fmt.Sprintf(" %v%v %v %v%v%v%v\n",
|
b.WriteString(fmt.Sprintf(" %v%v %v %v%v%v%v\n",
|
||||||
op.Prefix(), c, plural("resource", c), planTo, op, pastTense, colors.Reset))
|
op.Prefix(), c, plural("resource", c), planTo, op, pastTense, colors.Reset))
|
||||||
|
@ -288,40 +305,51 @@ func printUnchanged(b *bytes.Buffer, stats deploy.PlanSummary, summary bool, pla
|
||||||
for _, res := range stats.Resources() {
|
for _, res := range stats.Resources() {
|
||||||
if stats.Sames()[res.URN()] {
|
if stats.Sames()[res.URN()] {
|
||||||
b.WriteString(" ") // simulate the 2 spaces for +, -, etc.
|
b.WriteString(" ") // simulate the 2 spaces for +, -, etc.
|
||||||
printResourceHeader(b, res, nil, "")
|
printResourceHeader(b, res)
|
||||||
printResourceProperties(b, res.URN(), res, nil, nil, nil, summary, planning, "")
|
printResourceProperties(b, res.URN(), res, nil, nil, nil, summary, planning, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printStep(b *bytes.Buffer, step *deploy.Step, summary bool, planning bool, indent string) {
|
func printStep(b *bytes.Buffer, step deploy.Step, summary bool, planning bool, indent string) {
|
||||||
// First print out the operation's prefix.
|
// First print out the operation's prefix.
|
||||||
b.WriteString(step.Op().Prefix())
|
b.WriteString(step.Op().Prefix())
|
||||||
|
|
||||||
// Next print the resource URN, properties, etc.
|
// Next, print the resource type (since it is easy on the eyes and can be quickly identified).
|
||||||
printResourceHeader(b, step.Old(), step.New(), indent)
|
printStepHeader(b, step)
|
||||||
b.WriteString(step.Op().Suffix())
|
b.WriteString(step.Op().Suffix())
|
||||||
printResourceProperties(b, step.URN(), step.Old(), step.New(), step.Inputs(), step.Reasons(),
|
|
||||||
summary, planning, indent)
|
// Next print the resource URN, properties, etc.
|
||||||
|
if mut, ismut := step.(deploy.MutatingStep); ismut {
|
||||||
|
var replaces []resource.PropertyKey
|
||||||
|
if step.Op() == deploy.OpReplace {
|
||||||
|
replaces = step.(*deploy.ReplaceStep).Reasons()
|
||||||
|
}
|
||||||
|
printResourceProperties(b,
|
||||||
|
mut.URN(), mut.Old(), mut.New(), mut.Inputs(), replaces, summary, planning, indent)
|
||||||
|
} else if rd, isrd := step.(deploy.ReadStep); isrd {
|
||||||
|
for _, res := range rd.Resources() {
|
||||||
|
printResourceProperties(b,
|
||||||
|
"", nil, res, res.CopyProperties(), nil, summary, planning, indent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contract.Failf("Expected each step to either be mutating or read-only")
|
||||||
|
}
|
||||||
|
|
||||||
// Finally make sure to reset the color.
|
// Finally make sure to reset the color.
|
||||||
b.WriteString(colors.Reset)
|
b.WriteString(colors.Reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printResourceHeader(b *bytes.Buffer, old *resource.State, new *resource.Object, indent string) {
|
func printStepHeader(b *bytes.Buffer, step deploy.Step) {
|
||||||
var t tokens.Type
|
b.WriteString(fmt.Sprintf("%s:\n", string(step.Type())))
|
||||||
if old != nil {
|
}
|
||||||
t = old.Type()
|
|
||||||
} else {
|
|
||||||
t = new.Type()
|
|
||||||
}
|
|
||||||
|
|
||||||
// The primary header is the resource type (since it is easy on the eyes).
|
func printResourceHeader(b *bytes.Buffer, res resource.Resource) {
|
||||||
b.WriteString(fmt.Sprintf("%s:\n", string(t)))
|
b.WriteString(fmt.Sprintf("%s:\n", string(res.Type())))
|
||||||
}
|
}
|
||||||
|
|
||||||
func printResourceProperties(b *bytes.Buffer, urn resource.URN, old *resource.State, new *resource.Object,
|
func printResourceProperties(b *bytes.Buffer, urn resource.URN, old *resource.State, new *resource.Object,
|
||||||
inputs resource.PropertyMap, replaces []resource.PropertyKey, summary bool, planning bool, indent string) {
|
props resource.PropertyMap, replaces []resource.PropertyKey, summary bool, planning bool, indent string) {
|
||||||
indent += detailsIndent
|
indent += detailsIndent
|
||||||
|
|
||||||
// Print out the URN and, if present, the ID, as "pseudo-properties".
|
// Print out the URN and, if present, the ID, as "pseudo-properties".
|
||||||
|
@ -332,17 +360,19 @@ func printResourceProperties(b *bytes.Buffer, urn resource.URN, old *resource.St
|
||||||
if id != "" {
|
if id != "" {
|
||||||
b.WriteString(fmt.Sprintf("%s[id=%s]\n", indent, string(id)))
|
b.WriteString(fmt.Sprintf("%s[id=%s]\n", indent, string(id)))
|
||||||
}
|
}
|
||||||
b.WriteString(fmt.Sprintf("%s[urn=%s]\n", indent, urn))
|
if urn != "" {
|
||||||
|
b.WriteString(fmt.Sprintf("%s[urn=%s]\n", indent, urn))
|
||||||
|
}
|
||||||
|
|
||||||
if !summary {
|
if !summary {
|
||||||
// Print all of the properties associated with this resource.
|
// Print all of the properties associated with this resource.
|
||||||
if old == nil && new != nil {
|
if old == nil && new != nil {
|
||||||
printObject(b, inputs, planning, indent)
|
printObject(b, props, planning, indent)
|
||||||
} else if new == nil && old != nil {
|
} else if new == nil && old != nil {
|
||||||
printObject(b, old.Inputs(), planning, indent)
|
printObject(b, old.Inputs(), planning, indent)
|
||||||
} else {
|
} else {
|
||||||
contract.Assert(inputs != nil) // use computed properties for diffs.
|
contract.Assert(props != nil) // use computed properties for diffs.
|
||||||
printOldNewDiffs(b, old.Inputs(), inputs, replaces, planning, indent)
|
printOldNewDiffs(b, old.Inputs(), props, replaces, planning, indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,16 +403,22 @@ func printObject(b *bytes.Buffer, props resource.PropertyMap, planning bool, ind
|
||||||
|
|
||||||
// printResourceOutputProperties prints only those properties that either differ from the input properties or, if
|
// printResourceOutputProperties prints only those properties that either differ from the input properties or, if
|
||||||
// there is an old snapshot of the resource, differ from the prior old snapshot's output properties.
|
// there is an old snapshot of the resource, differ from the prior old snapshot's output properties.
|
||||||
func printResourceOutputProperties(b *bytes.Buffer, step *deploy.Step, indent string) {
|
func printResourceOutputProperties(b *bytes.Buffer, step deploy.Step, indent string) {
|
||||||
|
mut, ismut := step.(deploy.MutatingStep)
|
||||||
|
if !ismut {
|
||||||
|
// Only mutating steps have output properties associated with them.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
indent += detailsIndent
|
indent += detailsIndent
|
||||||
b.WriteString(step.Op().Color())
|
b.WriteString(step.Op().Color())
|
||||||
b.WriteString(step.Op().Suffix())
|
b.WriteString(step.Op().Suffix())
|
||||||
|
|
||||||
// First fetch all the relevant property maps that we may consult.
|
// First fetch all the relevant property maps that we may consult.
|
||||||
newins := step.Inputs()
|
newins := mut.Inputs()
|
||||||
newouts := step.Outputs()
|
newouts := mut.Outputs()
|
||||||
var oldouts resource.PropertyMap
|
var oldouts resource.PropertyMap
|
||||||
if old := step.Old(); old != nil {
|
if old := mut.Old(); old != nil {
|
||||||
oldouts = old.Outputs()
|
oldouts = old.Outputs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,12 +579,12 @@ func printPropertyValueDiff(b *bytes.Buffer, title func(string), diff resource.V
|
||||||
titleFunc := func(id string) { printArrayElemHeader(b, i, id) }
|
titleFunc := func(id string) { printArrayElemHeader(b, i, id) }
|
||||||
if add, isadd := a.Adds[i]; isadd {
|
if add, isadd := a.Adds[i]; isadd {
|
||||||
b.WriteString(deploy.OpCreate.Color())
|
b.WriteString(deploy.OpCreate.Color())
|
||||||
title(addIndent(indent))
|
titleFunc(addIndent(indent))
|
||||||
printPropertyValue(b, add, planning, addIndent(newIndent))
|
printPropertyValue(b, add, planning, addIndent(newIndent))
|
||||||
b.WriteString(colors.Reset)
|
b.WriteString(colors.Reset)
|
||||||
} else if delete, isdelete := a.Deletes[i]; isdelete {
|
} else if delete, isdelete := a.Deletes[i]; isdelete {
|
||||||
b.WriteString(deploy.OpDelete.Color())
|
b.WriteString(deploy.OpDelete.Color())
|
||||||
title(deleteIndent(indent))
|
titleFunc(deleteIndent(indent))
|
||||||
printPropertyValue(b, delete, planning, deleteIndent(newIndent))
|
printPropertyValue(b, delete, planning, deleteIndent(newIndent))
|
||||||
b.WriteString(colors.Reset)
|
b.WriteString(colors.Reset)
|
||||||
} else if update, isupdate := a.Updates[i]; isupdate {
|
} else if update, isupdate := a.Updates[i]; isupdate {
|
||||||
|
|
|
@ -15,6 +15,14 @@ export class Account extends lumi.NamedResource implements AccountArgs {
|
||||||
this.cloudWatchRole = args.cloudWatchRole;
|
this.cloudWatchRole = args.cloudWatchRole;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Account {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Account[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountArgs {
|
export interface AccountArgs {
|
||||||
|
|
|
@ -22,6 +22,14 @@ export class APIKey extends lumi.NamedResource implements APIKeyArgs {
|
||||||
this.stageKeys = args.stageKeys;
|
this.stageKeys = args.stageKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): APIKey {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): APIKey[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APIKeyArgs {
|
export interface APIKeyArgs {
|
||||||
|
|
|
@ -34,6 +34,14 @@ export class Authorizer extends lumi.NamedResource implements AuthorizerArgs {
|
||||||
this.providers = args.providers;
|
this.providers = args.providers;
|
||||||
this.restAPI = args.restAPI;
|
this.restAPI = args.restAPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Authorizer {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Authorizer[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthorizerArgs {
|
export interface AuthorizerArgs {
|
||||||
|
|
|
@ -26,6 +26,14 @@ export class BasePathMapping extends lumi.NamedResource implements BasePathMappi
|
||||||
this.basePath = args.basePath;
|
this.basePath = args.basePath;
|
||||||
this.stage = args.stage;
|
this.stage = args.stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): BasePathMapping {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): BasePathMapping[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BasePathMappingArgs {
|
export interface BasePathMappingArgs {
|
||||||
|
|
|
@ -13,6 +13,14 @@ export class ClientCertificate extends lumi.NamedResource implements ClientCerti
|
||||||
this.description = args.description;
|
this.description = args.description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): ClientCertificate {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): ClientCertificate[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientCertificateArgs {
|
export interface ClientCertificateArgs {
|
||||||
|
|
|
@ -20,6 +20,14 @@ export class Deployment extends lumi.NamedResource implements DeploymentArgs {
|
||||||
this.restAPI = args.restAPI;
|
this.restAPI = args.restAPI;
|
||||||
this.description = args.description;
|
this.description = args.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Deployment {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Deployment[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeploymentArgs {
|
export interface DeploymentArgs {
|
||||||
|
|
|
@ -97,6 +97,14 @@ export class Method extends lumi.NamedResource implements MethodArgs {
|
||||||
this.requestModels = args.requestModels;
|
this.requestModels = args.requestModels;
|
||||||
this.requestParameters = args.requestParameters;
|
this.requestParameters = args.requestParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Method {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Method[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MethodArgs {
|
export interface MethodArgs {
|
||||||
|
|
|
@ -30,6 +30,14 @@ export class Model extends lumi.NamedResource implements ModelArgs {
|
||||||
this.modelName = args.modelName;
|
this.modelName = args.modelName;
|
||||||
this.description = args.description;
|
this.description = args.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Model {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Model[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModelArgs {
|
export interface ModelArgs {
|
||||||
|
|
|
@ -26,6 +26,14 @@ export class Resource extends lumi.NamedResource implements ResourceArgs {
|
||||||
}
|
}
|
||||||
this.restAPI = args.restAPI;
|
this.restAPI = args.restAPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Resource {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Resource[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResourceArgs {
|
export interface ResourceArgs {
|
||||||
|
|
|
@ -32,6 +32,14 @@ export class RestAPI extends lumi.NamedResource implements RestAPIArgs {
|
||||||
this.parameters = args.parameters;
|
this.parameters = args.parameters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): RestAPI {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): RestAPI[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RestAPIArgs {
|
export interface RestAPIArgs {
|
||||||
|
|
|
@ -45,6 +45,14 @@ export class Stage extends lumi.NamedResource implements StageArgs {
|
||||||
this.methodSettings = args.methodSettings;
|
this.methodSettings = args.methodSettings;
|
||||||
this.variables = args.variables;
|
this.variables = args.variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Stage {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Stage[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StageArgs {
|
export interface StageArgs {
|
||||||
|
|
|
@ -49,6 +49,14 @@ export class UsagePlan extends lumi.NamedResource implements UsagePlanArgs {
|
||||||
this.usagePlanName = args.usagePlanName;
|
this.usagePlanName = args.usagePlanName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): UsagePlan {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): UsagePlan[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UsagePlanArgs {
|
export interface UsagePlanArgs {
|
||||||
|
|
|
@ -22,6 +22,14 @@ export class UsagePlanKey extends lumi.NamedResource implements UsagePlanKeyArgs
|
||||||
}
|
}
|
||||||
this.usagePlan = args.usagePlan;
|
this.usagePlan = args.usagePlan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): UsagePlanKey {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): UsagePlanKey[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UsagePlanKeyArgs {
|
export interface UsagePlanKeyArgs {
|
||||||
|
|
|
@ -56,6 +56,14 @@ export class ActionTarget extends lumi.NamedResource implements ActionTargetArgs
|
||||||
this.subscription = args.subscription;
|
this.subscription = args.subscription;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): ActionTarget {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): ActionTarget[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionTargetArgs {
|
export interface ActionTargetArgs {
|
||||||
|
@ -120,6 +128,14 @@ export class Alarm extends lumi.NamedResource implements AlarmArgs {
|
||||||
this.okActions = args.okActions;
|
this.okActions = args.okActions;
|
||||||
this.unit = args.unit;
|
this.unit = args.unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Alarm {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Alarm[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AlarmArgs {
|
export interface AlarmArgs {
|
||||||
|
|
|
@ -67,6 +67,14 @@ export class Table extends lumi.NamedResource implements TableArgs {
|
||||||
this.tableName = args.tableName;
|
this.tableName = args.tableName;
|
||||||
this.globalSecondaryIndexes = args.globalSecondaryIndexes;
|
this.globalSecondaryIndexes = args.globalSecondaryIndexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Table {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Table[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableArgs {
|
export interface TableArgs {
|
||||||
|
|
|
@ -87,6 +87,14 @@ export class Instance extends lumi.NamedResource implements InstanceArgs {
|
||||||
this.keyName = args.keyName;
|
this.keyName = args.keyName;
|
||||||
this.tags = args.tags;
|
this.tags = args.tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Instance {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Instance[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceArgs {
|
export interface InstanceArgs {
|
||||||
|
|
|
@ -9,6 +9,14 @@ export class InternetGateway extends lumi.NamedResource implements InternetGatew
|
||||||
constructor(name: string, args?: InternetGatewayArgs) {
|
constructor(name: string, args?: InternetGatewayArgs) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): InternetGateway {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): InternetGateway[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InternetGatewayArgs {
|
export interface InternetGatewayArgs {
|
||||||
|
|
|
@ -33,6 +33,14 @@ export class Route extends lumi.NamedResource implements RouteArgs {
|
||||||
}
|
}
|
||||||
this.vpcGatewayAttachment = args.vpcGatewayAttachment;
|
this.vpcGatewayAttachment = args.vpcGatewayAttachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Route {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Route[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RouteArgs {
|
export interface RouteArgs {
|
||||||
|
|
|
@ -16,6 +16,14 @@ export class RouteTable extends lumi.NamedResource implements RouteTableArgs {
|
||||||
}
|
}
|
||||||
this.vpc = args.vpc;
|
this.vpc = args.vpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): RouteTable {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): RouteTable[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RouteTableArgs {
|
export interface RouteTableArgs {
|
||||||
|
|
|
@ -25,6 +25,14 @@ export class SecurityGroup extends lumi.NamedResource implements SecurityGroupAr
|
||||||
this.securityGroupEgress = args.securityGroupEgress;
|
this.securityGroupEgress = args.securityGroupEgress;
|
||||||
this.securityGroupIngress = args.securityGroupIngress;
|
this.securityGroupIngress = args.securityGroupIngress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): SecurityGroup {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): SecurityGroup[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SecurityGroupArgs {
|
export interface SecurityGroupArgs {
|
||||||
|
|
|
@ -39,6 +39,14 @@ export class SecurityGroupEgress extends lumi.NamedResource implements SecurityG
|
||||||
this.destinationPrefixListId = args.destinationPrefixListId;
|
this.destinationPrefixListId = args.destinationPrefixListId;
|
||||||
this.destinationSecurityGroup = args.destinationSecurityGroup;
|
this.destinationSecurityGroup = args.destinationSecurityGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): SecurityGroupEgress {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): SecurityGroupEgress[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SecurityGroupEgressArgs {
|
export interface SecurityGroupEgressArgs {
|
||||||
|
|
|
@ -34,6 +34,14 @@ export class SecurityGroupIngress extends lumi.NamedResource implements Security
|
||||||
this.sourceSecurityGroupOwnerId = args.sourceSecurityGroupOwnerId;
|
this.sourceSecurityGroupOwnerId = args.sourceSecurityGroupOwnerId;
|
||||||
this.toPort = args.toPort;
|
this.toPort = args.toPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): SecurityGroupIngress {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): SecurityGroupIngress[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SecurityGroupIngressArgs {
|
export interface SecurityGroupIngressArgs {
|
||||||
|
|
|
@ -25,6 +25,14 @@ export class Subnet extends lumi.NamedResource implements SubnetArgs {
|
||||||
this.availabilityZone = args.availabilityZone;
|
this.availabilityZone = args.availabilityZone;
|
||||||
this.mapPublicIpOnLaunch = args.mapPublicIpOnLaunch;
|
this.mapPublicIpOnLaunch = args.mapPublicIpOnLaunch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Subnet {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Subnet[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SubnetArgs {
|
export interface SubnetArgs {
|
||||||
|
|
|
@ -29,6 +29,14 @@ export class VPC extends lumi.NamedResource implements VPCArgs {
|
||||||
this.enableDnsSupport = args.enableDnsSupport;
|
this.enableDnsSupport = args.enableDnsSupport;
|
||||||
this.enableDnsHostnames = args.enableDnsHostnames;
|
this.enableDnsHostnames = args.enableDnsHostnames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): VPC {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): VPC[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VPCArgs {
|
export interface VPCArgs {
|
||||||
|
|
|
@ -22,6 +22,14 @@ export class VPCGatewayAttachment extends lumi.NamedResource implements VPCGatew
|
||||||
}
|
}
|
||||||
this.internetGateway = args.internetGateway;
|
this.internetGateway = args.internetGateway;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): VPCGatewayAttachment {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): VPCGatewayAttachment[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VPCGatewayAttachmentArgs {
|
export interface VPCGatewayAttachmentArgs {
|
||||||
|
|
|
@ -21,6 +21,14 @@ export class VPCPeeringConnection extends lumi.NamedResource implements VPCPeeri
|
||||||
}
|
}
|
||||||
this.vpc = args.vpc;
|
this.vpc = args.vpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): VPCPeeringConnection {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): VPCPeeringConnection[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VPCPeeringConnectionArgs {
|
export interface VPCPeeringConnectionArgs {
|
||||||
|
|
|
@ -15,6 +15,14 @@ export class Application extends lumi.NamedResource implements ApplicationArgs {
|
||||||
this.description = args.description;
|
this.description = args.description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Application {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Application[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApplicationArgs {
|
export interface ApplicationArgs {
|
||||||
|
|
|
@ -26,6 +26,14 @@ export class ApplicationVersion extends lumi.NamedResource implements Applicatio
|
||||||
}
|
}
|
||||||
this.sourceBundle = args.sourceBundle;
|
this.sourceBundle = args.sourceBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): ApplicationVersion {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): ApplicationVersion[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApplicationVersionArgs {
|
export interface ApplicationVersionArgs {
|
||||||
|
|
|
@ -40,6 +40,14 @@ export class Environment extends lumi.NamedResource implements EnvironmentArgs {
|
||||||
this.tier = args.tier;
|
this.tier = args.tier;
|
||||||
this.version = args.version;
|
this.version = args.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Environment {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Environment[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EnvironmentArgs {
|
export interface EnvironmentArgs {
|
||||||
|
|
|
@ -21,6 +21,14 @@ export class Group extends lumi.NamedResource implements GroupArgs {
|
||||||
this.policies = args.policies;
|
this.policies = args.policies;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Group {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Group[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GroupArgs {
|
export interface GroupArgs {
|
||||||
|
|
|
@ -34,6 +34,14 @@ export class Policy extends lumi.NamedResource implements PolicyArgs {
|
||||||
this.roles = args.roles;
|
this.roles = args.roles;
|
||||||
this.users = args.users;
|
this.users = args.users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Policy {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Policy[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PolicyArgs {
|
export interface PolicyArgs {
|
||||||
|
|
|
@ -26,6 +26,14 @@ export class Role extends lumi.NamedResource implements RoleArgs {
|
||||||
this.managedPolicyARNs = args.managedPolicyARNs;
|
this.managedPolicyARNs = args.managedPolicyARNs;
|
||||||
this.policies = args.policies;
|
this.policies = args.policies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Role {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Role[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoleArgs {
|
export interface RoleArgs {
|
||||||
|
|
|
@ -31,6 +31,14 @@ export class User extends lumi.NamedResource implements UserArgs {
|
||||||
this.policies = args.policies;
|
this.policies = args.policies;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): User {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): User[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserArgs {
|
export interface UserArgs {
|
||||||
|
|
|
@ -20,6 +20,14 @@ export class Key extends lumi.NamedResource implements KeyArgs {
|
||||||
this.enabled = args.enabled;
|
this.enabled = args.enabled;
|
||||||
this.enableKeyRotation = args.enableKeyRotation;
|
this.enableKeyRotation = args.enableKeyRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Key {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Key[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface KeyArgs {
|
export interface KeyArgs {
|
||||||
|
|
|
@ -69,6 +69,14 @@ export class Function extends lumi.NamedResource implements FunctionArgs {
|
||||||
this.timeout = args.timeout;
|
this.timeout = args.timeout;
|
||||||
this.vpcConfig = args.vpcConfig;
|
this.vpcConfig = args.vpcConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Function {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Function[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FunctionArgs {
|
export interface FunctionArgs {
|
||||||
|
|
|
@ -31,6 +31,14 @@ export class Permission extends lumi.NamedResource implements PermissionArgs {
|
||||||
this.sourceAccount = args.sourceAccount;
|
this.sourceAccount = args.sourceAccount;
|
||||||
this.sourceARN = args.sourceARN;
|
this.sourceARN = args.sourceARN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Permission {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Permission[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PermissionArgs {
|
export interface PermissionArgs {
|
||||||
|
|
|
@ -17,6 +17,14 @@ export class Bucket extends lumi.NamedResource implements BucketArgs {
|
||||||
this.accessControl = args.accessControl;
|
this.accessControl = args.accessControl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Bucket {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Bucket[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BucketArgs {
|
export interface BucketArgs {
|
||||||
|
|
|
@ -26,6 +26,14 @@ export class Object extends lumi.Resource implements ObjectArgs {
|
||||||
}
|
}
|
||||||
this.source = args.source;
|
this.source = args.source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Object {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Object[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ObjectArgs {
|
export interface ObjectArgs {
|
||||||
|
|
|
@ -26,6 +26,14 @@ export class Topic extends lumi.NamedResource implements TopicArgs {
|
||||||
this.subscription = args.subscription;
|
this.subscription = args.subscription;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Topic {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Topic[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TopicArgs {
|
export interface TopicArgs {
|
||||||
|
|
|
@ -29,6 +29,14 @@ export class Queue extends lumi.NamedResource implements QueueArgs {
|
||||||
this.visibilityTimeout = args.visibilityTimeout;
|
this.visibilityTimeout = args.visibilityTimeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get(id: lumi.ID): Queue {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static query(q: any): Queue[] {
|
||||||
|
return <any>undefined; // functionality provided by the runtime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueueArgs {
|
export interface QueueArgs {
|
||||||
|
|
|
@ -13,10 +13,13 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
export type ID = string;
|
||||||
|
export type URN = string;
|
||||||
|
|
||||||
// Resource represents a class whose CRUD operations are implemented by a provider plugin.
|
// Resource represents a class whose CRUD operations are implemented by a provider plugin.
|
||||||
export abstract class Resource {
|
export abstract class Resource {
|
||||||
public readonly id: string; // the provider-assigned unique ID (initialized by the runtime).
|
public readonly id: ID; // the provider-assigned unique ID (initialized by the runtime).
|
||||||
public readonly urn: string; // the Lumi URN (initialized by the runtime).
|
public readonly urn: URN; // the Lumi URN (initialized by the runtime).
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamedResource is a kind of resource that has a friendly resource name associated with it.
|
// NamedResource is a kind of resource that has a friendly resource name associated with it.
|
||||||
|
|
|
@ -81,6 +81,7 @@ var (
|
||||||
|
|
||||||
SpecAdded = Green // for adds (in the diff sense).
|
SpecAdded = Green // for adds (in the diff sense).
|
||||||
SpecChanged = BrightYellow // for changes (in the diff sense).
|
SpecChanged = BrightYellow // for changes (in the diff sense).
|
||||||
|
SpecRead = BrightWhite // for reads (relatively unimportant).
|
||||||
SpecReplaced = Yellow // for replacements (in the diff sense).
|
SpecReplaced = Yellow // for replacements (in the diff sense).
|
||||||
SpecDeleted = Red // for deletes (in the diff sense).
|
SpecDeleted = Red // for deletes (in the diff sense).
|
||||||
)
|
)
|
||||||
|
|
|
@ -701,13 +701,6 @@ func (e *evaluator) evalCall(node diag.Diagable,
|
||||||
e.pushScope(frame, !shareActivation)
|
e.pushScope(frame, !shareActivation)
|
||||||
defer e.popScope(frame)
|
defer e.popScope(frame)
|
||||||
|
|
||||||
// Invoke the hooks if available.
|
|
||||||
if e.hooks != nil {
|
|
||||||
if leave := e.hooks.OnEnterFunction(sym); leave != nil {
|
|
||||||
defer leave()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the target is an instance method, the "this" and "super" variables must be bound to values.
|
// If the target is an instance method, the "this" and "super" variables must be bound to values.
|
||||||
if thisVariable != nil {
|
if thisVariable != nil {
|
||||||
contract.Assert(this != nil)
|
contract.Assert(this != nil)
|
||||||
|
@ -740,14 +733,26 @@ func (e *evaluator) evalCall(node diag.Diagable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now perform the invocation; for intrinsics, just run the code; for all others, interpret the body.
|
|
||||||
var uw *rt.Unwind
|
var uw *rt.Unwind
|
||||||
if intrinsic {
|
|
||||||
isym := sym.(*rt.Intrinsic)
|
// Invoke the hooks if available.
|
||||||
invoker := GetIntrinsicInvoker(isym)
|
if e.hooks != nil {
|
||||||
uw = invoker(isym, e, this, args)
|
var leave func()
|
||||||
} else {
|
if uw, leave = e.hooks.OnEnterFunction(sym, args); leave != nil {
|
||||||
uw = e.evalStatement(fnc.GetBody())
|
defer leave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming the hook didn't perform its own logic, we can now perform the real invocation; for intrinsics, just run
|
||||||
|
// the code; for all others, interpret the body.
|
||||||
|
if uw == nil {
|
||||||
|
if intrinsic {
|
||||||
|
isym := sym.(*rt.Intrinsic)
|
||||||
|
invoker := GetIntrinsicInvoker(isym)
|
||||||
|
uw = invoker(isym, e, this, args)
|
||||||
|
} else {
|
||||||
|
uw = e.evalStatement(fnc.GetBody())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the unwind is as expected. In particular:
|
// Check that the unwind is as expected. In particular:
|
||||||
|
|
|
@ -30,7 +30,7 @@ type Hooks interface {
|
||||||
// OnEnterModule is invoked whenever we enter a module.
|
// OnEnterModule is invoked whenever we enter a module.
|
||||||
OnEnterModule(sym *symbols.Module) func()
|
OnEnterModule(sym *symbols.Module) func()
|
||||||
// OnEnterFunction is invoked whenever we enter a function.
|
// OnEnterFunction is invoked whenever we enter a function.
|
||||||
OnEnterFunction(fnc symbols.Function) func()
|
OnEnterFunction(fnc symbols.Function, args []*rt.Object) (*rt.Unwind, func())
|
||||||
// OnObjectInit is invoked after an object has been allocated and initialized. This means that its constructor, if
|
// OnObjectInit is invoked after an object has been allocated and initialized. This means that its constructor, if
|
||||||
// any, has been run to completion. The diagnostics tree is the AST node responsible for the allocation.
|
// any, has been run to completion. The diagnostics tree is the AST node responsible for the allocation.
|
||||||
OnObjectInit(tree diag.Diagable, o *rt.Object)
|
OnObjectInit(tree diag.Diagable, o *rt.Object)
|
||||||
|
|
|
@ -82,7 +82,12 @@ func (p *Plan) New() Source { return p.new }
|
||||||
// Provider fetches the provider for a given resource, possibly lazily allocating the plugins for it. If a provider
|
// Provider fetches the provider for a given resource, possibly lazily allocating the plugins for it. If a provider
|
||||||
// could not be found, or an error occurred while creating it, a non-nil error is returned.
|
// could not be found, or an error occurred while creating it, a non-nil error is returned.
|
||||||
func (p *Plan) Provider(res resource.Resource) (plugin.Provider, error) {
|
func (p *Plan) Provider(res resource.Resource) (plugin.Provider, error) {
|
||||||
t := res.Type()
|
return p.ProviderT(res.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderT fetches the provider for a given resource type, possibly lazily allocating the plugins for it. If a
|
||||||
|
// provider could not be found, or an error occurred while creating it, a non-nil error is returned.
|
||||||
|
func (p *Plan) ProviderT(t tokens.Type) (plugin.Provider, error) {
|
||||||
pkg := t.Package()
|
pkg := t.Package()
|
||||||
return p.ctx.Host.Provider(pkg)
|
return p.ctx.Host.Provider(pkg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"github.com/pulumi/lumi/pkg/compiler/errors"
|
"github.com/pulumi/lumi/pkg/compiler/errors"
|
||||||
"github.com/pulumi/lumi/pkg/resource"
|
"github.com/pulumi/lumi/pkg/resource"
|
||||||
"github.com/pulumi/lumi/pkg/resource/plugin"
|
"github.com/pulumi/lumi/pkg/resource/plugin"
|
||||||
"github.com/pulumi/lumi/pkg/tokens"
|
|
||||||
"github.com/pulumi/lumi/pkg/util/contract"
|
"github.com/pulumi/lumi/pkg/util/contract"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ import (
|
||||||
// Apply performs all steps in the plan, calling out to the progress reporting functions as desired. It returns four
|
// Apply performs all steps in the plan, calling out to the progress reporting functions as desired. It returns four
|
||||||
// things: the resulting Snapshot, no matter whether an error occurs or not; an error, if something went wrong; the step
|
// things: the resulting Snapshot, no matter whether an error occurs or not; an error, if something went wrong; the step
|
||||||
// that failed, if the error is non-nil; and finally the state of the resource modified in the failing step.
|
// that failed, if the error is non-nil; and finally the state of the resource modified in the failing step.
|
||||||
func (p *Plan) Apply(prog Progress) (PlanSummary, *Step, resource.Status, error) {
|
func (p *Plan) Apply(prog Progress) (PlanSummary, Step, resource.Status, error) {
|
||||||
// Fetch a plan iterator and keep walking it until we are done.
|
// Fetch a plan iterator and keep walking it until we are done.
|
||||||
iter, err := p.Iterate()
|
iter, err := p.Iterate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -43,12 +42,18 @@ func (p *Plan) Apply(prog Progress) (PlanSummary, *Step, resource.Status, error)
|
||||||
return nil, nil, resource.StatusOK, err
|
return nil, nil, resource.StatusOK, err
|
||||||
}
|
}
|
||||||
for step != nil {
|
for step != nil {
|
||||||
|
// Do the pre-step.
|
||||||
|
rst := resource.StatusOK
|
||||||
|
err := step.Pre()
|
||||||
|
|
||||||
// Perform pre-application progress reporting.
|
// Perform pre-application progress reporting.
|
||||||
if prog != nil {
|
if prog != nil {
|
||||||
prog.Before(step)
|
prog.Before(step)
|
||||||
}
|
}
|
||||||
|
|
||||||
rst, err := step.Apply()
|
if err == nil {
|
||||||
|
rst, err = step.Apply()
|
||||||
|
}
|
||||||
|
|
||||||
// Perform post-application progress reporting.
|
// Perform post-application progress reporting.
|
||||||
if prog != nil {
|
if prog != nil {
|
||||||
|
@ -135,33 +140,43 @@ func (iter *PlanIterator) Resources() []*resource.State { return iter.resourc
|
||||||
func (iter *PlanIterator) Dones() map[*resource.State]bool { return iter.dones }
|
func (iter *PlanIterator) Dones() map[*resource.State]bool { return iter.dones }
|
||||||
func (iter *PlanIterator) Done() bool { return iter.done }
|
func (iter *PlanIterator) Done() bool { return iter.done }
|
||||||
|
|
||||||
|
// Produce is used to indicate that a new resource state has been read from a live environment.
|
||||||
|
func (iter *PlanIterator) Produce(res *resource.Object) {
|
||||||
|
iter.src.Produce(res)
|
||||||
|
}
|
||||||
|
|
||||||
// Next advances the plan by a single step, and returns the next step to be performed. In doing so, it will perform
|
// Next advances the plan by a single step, and returns the next step to be performed. In doing so, it will perform
|
||||||
// evaluation of the program as much as necessary to determine the next step. If there is no further action to be
|
// evaluation of the program as much as necessary to determine the next step. If there is no further action to be
|
||||||
// taken, Next will return a nil step pointer.
|
// taken, Next will return a nil step pointer.
|
||||||
func (iter *PlanIterator) Next() (*Step, error) {
|
func (iter *PlanIterator) Next() (Step, error) {
|
||||||
for !iter.done {
|
for !iter.done {
|
||||||
if !iter.srcdone {
|
if !iter.srcdone {
|
||||||
obj, ctx, err := iter.src.Next()
|
res, q, err := iter.src.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if obj == nil {
|
} else if res != nil {
|
||||||
// If the source is done, note it, and don't go back for more.
|
step, err := iter.nextResourceStep(res)
|
||||||
iter.srcdone = true
|
|
||||||
iter.delqueue = iter.calculateDeletes()
|
|
||||||
} else {
|
|
||||||
step, err := iter.nextResource(obj, ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if step != nil {
|
|
||||||
return step, nil
|
|
||||||
}
|
}
|
||||||
|
contract.Assert(step != nil)
|
||||||
// If the step returned was nil, this resource is fine, so we'll keep on going.
|
return step, nil
|
||||||
continue
|
} else if q != nil {
|
||||||
|
step, err := iter.nextQueryStep(q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
contract.Assert(step != nil)
|
||||||
|
return step, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If all returns are nil, the source is done, note it, and don't go back for more. Add any deletions to be
|
||||||
|
// performed, and then keep going 'round the next iteration of the loop so we can wrap up the planning.
|
||||||
|
iter.srcdone = true
|
||||||
|
iter.delqueue = iter.calculateDeletes()
|
||||||
} else {
|
} else {
|
||||||
// The interpreter has finished, so we need to now drain any deletions that piled up.
|
// The interpreter has finished, so we need to now drain any deletions that piled up.
|
||||||
if step := iter.nextDelete(); step != nil {
|
if step := iter.nextDeleteStep(); step != nil {
|
||||||
return step, nil
|
return step, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,9 +188,10 @@ func (iter *PlanIterator) Next() (*Step, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextResource produces a new step for a given resource or nil if there isn't one to perform.
|
// nextResourceStep produces a new step for a given resource or nil if there isn't one to perform.
|
||||||
func (iter *PlanIterator) nextResource(new *resource.Object, ctx tokens.Module) (*Step, error) {
|
func (iter *PlanIterator) nextResourceStep(res *SourceAllocation) (Step, error) {
|
||||||
// Take a moment in time snapshot of the live object's properties.
|
// Take a moment in time snapshot of the live object's properties.
|
||||||
|
new := res.Obj
|
||||||
t := new.Type()
|
t := new.Type()
|
||||||
inputs := new.CopyProperties()
|
inputs := new.CopyProperties()
|
||||||
|
|
||||||
|
@ -190,7 +206,7 @@ func (iter *PlanIterator) nextResource(new *resource.Object, ctx tokens.Module)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
urn := resource.NewURN(iter.p.Target().Name, ctx, t, name)
|
urn := resource.NewURN(iter.p.Target().Name, res.Ctx, t, name)
|
||||||
|
|
||||||
// First ensure the provider is okay with this resource.
|
// First ensure the provider is okay with this resource.
|
||||||
var invalid bool
|
var invalid bool
|
||||||
|
@ -259,7 +275,7 @@ func (iter *PlanIterator) nextResource(new *resource.Object, ctx tokens.Module)
|
||||||
} else if len(replacements) > 0 {
|
} else if len(replacements) > 0 {
|
||||||
iter.replaces[urn] = true
|
iter.replaces[urn] = true
|
||||||
glog.V(7).Infof("Planner decided to replace '%v' (oldprops=%v inputs=%v)", urn, oldprops, inputs)
|
glog.V(7).Infof("Planner decided to replace '%v' (oldprops=%v inputs=%v)", urn, oldprops, inputs)
|
||||||
return NewReplaceCreateStep(iter, old, new, inputs, replacements), nil
|
return NewReplaceStep(iter, old, new, inputs, replacements), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
iter.updates[urn] = true
|
iter.updates[urn] = true
|
||||||
|
@ -273,8 +289,18 @@ func (iter *PlanIterator) nextResource(new *resource.Object, ctx tokens.Module)
|
||||||
return NewCreateStep(iter, urn, new, inputs), nil
|
return NewCreateStep(iter, urn, new, inputs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextDelete produces a new step that deletes a resource if necessary.
|
// nextQueryStep produces a new query step that looks up a resource in some manner.
|
||||||
func (iter *PlanIterator) nextDelete() *Step {
|
func (iter *PlanIterator) nextQueryStep(q *SourceQuery) (Step, error) {
|
||||||
|
if id := q.GetID; id != "" {
|
||||||
|
return NewGetStep(iter, q.Type, id, nil), nil
|
||||||
|
}
|
||||||
|
contract.Assert(q.QueryFilter != nil)
|
||||||
|
contract.Failf("TODO[pulumi/lumi#83]: querying not yet supported")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// nextDeleteStep produces a new step that deletes a resource if necessary.
|
||||||
|
func (iter *PlanIterator) nextDeleteStep() Step {
|
||||||
if len(iter.delqueue) > 0 {
|
if len(iter.delqueue) > 0 {
|
||||||
del := iter.delqueue[0]
|
del := iter.delqueue[0]
|
||||||
iter.delqueue = iter.delqueue[1:]
|
iter.delqueue = iter.delqueue[1:]
|
||||||
|
@ -282,10 +308,10 @@ func (iter *PlanIterator) nextDelete() *Step {
|
||||||
iter.deletes[urn] = true
|
iter.deletes[urn] = true
|
||||||
if iter.replaces[urn] {
|
if iter.replaces[urn] {
|
||||||
glog.V(7).Infof("Planner decided to delete '%v' due to replacement", urn)
|
glog.V(7).Infof("Planner decided to delete '%v' due to replacement", urn)
|
||||||
return NewReplaceDeleteStep(iter, del)
|
} else {
|
||||||
|
glog.V(7).Infof("Planner decided to delete '%v'", urn)
|
||||||
}
|
}
|
||||||
glog.V(7).Infof("Planner decided to delete '%v'", urn)
|
return NewDeleteStep(iter, del, iter.replaces[urn])
|
||||||
return NewDeleteStep(iter, del)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,8 +116,12 @@ func (iter *errorSourceIterator) Close() error {
|
||||||
return nil // nothing to do.
|
return nil // nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *errorSourceIterator) Next() (*resource.Object, tokens.Module, error) {
|
func (iter *errorSourceIterator) Produce(res *resource.Object) {
|
||||||
return nil, "", iter.src.err
|
// nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *errorSourceIterator) Next() (*SourceAllocation, *SourceQuery, error) {
|
||||||
|
return nil, nil, iter.src.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBasicCRUDPlan creates a plan with numerous C(R)UD operations.
|
// TestBasicCRUDPlan creates a plan with numerous C(R)UD operations.
|
||||||
|
@ -236,44 +240,48 @@ func TestBasicCRUDPlan(t *testing.T) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = step.Pre()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
var urn resource.URN
|
var urn resource.URN
|
||||||
var realID bool
|
var realID bool
|
||||||
var expectOuts resource.PropertyMap
|
var expectOuts resource.PropertyMap
|
||||||
var obj *resource.Object
|
var obj *resource.Object
|
||||||
op := step.Op()
|
switch s := step.(type) {
|
||||||
switch op {
|
case *CreateStep: // A is created
|
||||||
case OpCreate: // A is created
|
old := s.Old()
|
||||||
old := step.Old()
|
new := s.New()
|
||||||
new := step.New()
|
|
||||||
assert.Nil(t, old)
|
assert.Nil(t, old)
|
||||||
assert.NotNil(t, new)
|
assert.NotNil(t, new)
|
||||||
assert.Equal(t, newResAProps, step.Inputs())
|
assert.Equal(t, newResAProps, s.Inputs())
|
||||||
obj, urn, realID = new, urnA, false
|
obj, urn, realID = new, urnA, false
|
||||||
case OpUpdate: // B is updated
|
case *UpdateStep: // B is updated
|
||||||
old := step.Old()
|
old := s.Old()
|
||||||
new := step.New()
|
new := s.New()
|
||||||
assert.NotNil(t, old)
|
assert.NotNil(t, old)
|
||||||
assert.Equal(t, urnB, old.URN())
|
assert.Equal(t, urnB, old.URN())
|
||||||
assert.Equal(t, oldResB, old)
|
assert.Equal(t, oldResB, old)
|
||||||
assert.NotNil(t, new)
|
assert.NotNil(t, new)
|
||||||
assert.Equal(t, newResBProps, step.Inputs())
|
assert.Equal(t, newResBProps, s.Inputs())
|
||||||
obj, urn, realID = new, urnB, true
|
obj, urn, realID = new, urnB, true
|
||||||
case OpSame: // C is the same
|
case *SameStep: // C is the same
|
||||||
old := step.Old()
|
old := s.Old()
|
||||||
new := step.New()
|
new := s.New()
|
||||||
assert.NotNil(t, old)
|
assert.NotNil(t, old)
|
||||||
assert.Equal(t, urnC, old.URN())
|
assert.Equal(t, urnC, old.URN())
|
||||||
assert.Equal(t, oldResC, old)
|
assert.Equal(t, oldResC, old)
|
||||||
assert.NotNil(t, new)
|
assert.NotNil(t, new)
|
||||||
assert.Equal(t, newResCProps, step.Inputs())
|
assert.Equal(t, newResCProps, s.Inputs())
|
||||||
obj, urn, realID, expectOuts = new, urnC, true, oldResC.Outputs()
|
obj, urn, realID, expectOuts = new, urnC, true, oldResC.Outputs()
|
||||||
case OpDelete: // D is deleted
|
case *DeleteStep: // D is deleted
|
||||||
old := step.Old()
|
old := s.Old()
|
||||||
new := step.New()
|
new := s.New()
|
||||||
assert.NotNil(t, old)
|
assert.NotNil(t, old)
|
||||||
assert.Equal(t, urnD, old.URN())
|
assert.Equal(t, urnD, old.URN())
|
||||||
assert.Equal(t, oldResD, old)
|
assert.Equal(t, oldResD, old)
|
||||||
assert.Nil(t, new)
|
assert.Nil(t, new)
|
||||||
|
default:
|
||||||
|
t.FailNow() // unexpected step kind.
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
|
@ -292,8 +300,10 @@ func TestBasicCRUDPlan(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
step.Skip()
|
err = step.Skip()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
op := step.Op()
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
// Ensure the ID and URN are populated correctly.
|
// Ensure the ID and URN are populated correctly.
|
||||||
if realID {
|
if realID {
|
||||||
|
@ -317,8 +327,9 @@ func TestBasicCRUDPlan(t *testing.T) {
|
||||||
assert.Equal(t, 1, seen[OpCreate])
|
assert.Equal(t, 1, seen[OpCreate])
|
||||||
assert.Equal(t, 1, seen[OpUpdate])
|
assert.Equal(t, 1, seen[OpUpdate])
|
||||||
assert.Equal(t, 1, seen[OpDelete])
|
assert.Equal(t, 1, seen[OpDelete])
|
||||||
assert.Equal(t, 0, seen[OpReplaceCreate])
|
assert.Equal(t, 0, seen[OpReplace])
|
||||||
assert.Equal(t, 0, seen[OpReplaceDelete])
|
assert.Equal(t, 0, seen[OpGet])
|
||||||
|
assert.Equal(t, 0, seen[OpQuery])
|
||||||
|
|
||||||
assert.Equal(t, 1, len(iter.Creates()))
|
assert.Equal(t, 1, len(iter.Creates()))
|
||||||
assert.True(t, iter.Creates()[urnA])
|
assert.True(t, iter.Creates()[urnA])
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
// Progress can be used for progress reporting.
|
// Progress can be used for progress reporting.
|
||||||
type Progress interface {
|
type Progress interface {
|
||||||
// Before is invoked prior to a step executing.
|
// Before is invoked prior to a step executing.
|
||||||
Before(step *Step)
|
Before(step Step)
|
||||||
// After is invoked after a step executes, and is given access to the error, if any, that occurred.
|
// After is invoked after a step executes, and is given access to the error, if any, that occurred.
|
||||||
After(step *Step, state resource.Status, err error)
|
After(step Step, state resource.Status, err error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package deploy
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/pulumi/lumi/pkg/compiler/symbols"
|
||||||
"github.com/pulumi/lumi/pkg/resource"
|
"github.com/pulumi/lumi/pkg/resource"
|
||||||
"github.com/pulumi/lumi/pkg/tokens"
|
"github.com/pulumi/lumi/pkg/tokens"
|
||||||
)
|
)
|
||||||
|
@ -34,8 +35,23 @@ type Source interface {
|
||||||
// A SourceIterator enumerates the list of resources that a source has to offer.
|
// A SourceIterator enumerates the list of resources that a source has to offer.
|
||||||
type SourceIterator interface {
|
type SourceIterator interface {
|
||||||
io.Closer
|
io.Closer
|
||||||
// Next returns the next resource object plus a token context (usually where it was allocated); the token is used in
|
// Produce registers a resource that was produced during the iteration, to publish next time.
|
||||||
// the production of the ensuing resource's URN. If something went wrong, error is non-nil. If both error and the
|
Produce(res *resource.Object)
|
||||||
// resource are nil, then the iterator has completed its job and no subsequent calls to next should be made.
|
// Next returns the next step from the source. If the source allocation is non-nil, it represents the creation of
|
||||||
Next() (*resource.Object, tokens.Module, error)
|
// a resource object; if query is non-nil, it represents querying the resources; if both error and the other
|
||||||
|
// objects are nil, then the iterator has completed its job and no subsequent calls to next should be made.
|
||||||
|
Next() (*SourceAllocation, *SourceQuery, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SourceAllocation is used when a resource object is allocated.
|
||||||
|
type SourceAllocation struct {
|
||||||
|
Obj *resource.Object // the resource object.
|
||||||
|
Ctx tokens.Module // the context in which the resource was allocated, used in the production of URNs.
|
||||||
|
}
|
||||||
|
|
||||||
|
// SourceQuery is used when a query function is to be performed.
|
||||||
|
type SourceQuery struct {
|
||||||
|
Type symbols.Type // the type of resource being queried.
|
||||||
|
GetID resource.ID // the resource ID to get (for gets only).
|
||||||
|
QueryFilter resource.PropertyMap // the query's filter (for queries only).
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/pulumi/lumi/pkg/compiler/core"
|
"github.com/pulumi/lumi/pkg/compiler/core"
|
||||||
"github.com/pulumi/lumi/pkg/compiler/errors"
|
"github.com/pulumi/lumi/pkg/compiler/errors"
|
||||||
"github.com/pulumi/lumi/pkg/compiler/symbols"
|
"github.com/pulumi/lumi/pkg/compiler/symbols"
|
||||||
|
"github.com/pulumi/lumi/pkg/compiler/types/predef"
|
||||||
"github.com/pulumi/lumi/pkg/diag"
|
"github.com/pulumi/lumi/pkg/diag"
|
||||||
"github.com/pulumi/lumi/pkg/eval"
|
"github.com/pulumi/lumi/pkg/eval"
|
||||||
"github.com/pulumi/lumi/pkg/eval/rt"
|
"github.com/pulumi/lumi/pkg/eval/rt"
|
||||||
|
@ -100,6 +101,7 @@ func (src *evalSource) Iterate() (SourceIterator, error) {
|
||||||
type evalSourceIterator struct {
|
type evalSourceIterator struct {
|
||||||
src *evalSource // the owning eval source object.
|
src *evalSource // the owning eval source object.
|
||||||
e eval.Interpreter // the interpreter used to compute the new state.
|
e eval.Interpreter // the interpreter used to compute the new state.
|
||||||
|
res *resource.Object // a resource to publish during the next rendezvous.
|
||||||
rz *rendezvous.Rendezvous // the rendezvous where planning and evaluator coroutines meet.
|
rz *rendezvous.Rendezvous // the rendezvous where planning and evaluator coroutines meet.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,21 +111,57 @@ func (iter *evalSourceIterator) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *evalSourceIterator) Next() (*resource.Object, tokens.Module, error) {
|
func (iter *evalSourceIterator) Produce(res *resource.Object) {
|
||||||
|
iter.res = res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *evalSourceIterator) Next() (*SourceAllocation, *SourceQuery, error) {
|
||||||
// Kick the interpreter to compute some more and then inspect what it has to say.
|
// Kick the interpreter to compute some more and then inspect what it has to say.
|
||||||
obj, done, err := iter.rz.Meet(planParty, nil)
|
var data interface{}
|
||||||
|
if res := iter.res; res != nil {
|
||||||
|
data = rt.NewReturnUnwind(res.Obj())
|
||||||
|
iter.res = nil // reset the state so we don't return things more than once.
|
||||||
|
}
|
||||||
|
obj, done, err := iter.rz.Meet(planParty, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, nil, err
|
||||||
} else if done {
|
} else if done {
|
||||||
glog.V(5).Infof("EvalSourceIterator is done")
|
glog.V(5).Infof("EvalSourceIterator is done")
|
||||||
return nil, "", nil
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
contract.Assert(obj != nil)
|
||||||
|
|
||||||
|
// See what the interpreter came up with. It's either an allocation or a query operation.
|
||||||
|
if alloc, isalloc := obj.(*AllocRendezvous); isalloc {
|
||||||
|
glog.V(5).Infof("EvalSourceIterator produced a new object: obj=%v, ctx=%v", alloc.Obj, alloc.Mod.Tok)
|
||||||
|
return &SourceAllocation{
|
||||||
|
Obj: resource.NewObject(alloc.Obj),
|
||||||
|
Ctx: alloc.Mod.Tok,
|
||||||
|
}, nil, nil
|
||||||
|
} else if query, isquery := obj.(*QueryRendezvous); isquery {
|
||||||
|
glog.V(5).Infof("EvalSourceIterator produced a new query: fnc=%v, #args=%v", query.Meth, len(query.Args))
|
||||||
|
meth := query.Meth
|
||||||
|
args := query.Args
|
||||||
|
t := meth.Parent
|
||||||
|
switch meth.Name() {
|
||||||
|
case specialResourceGetFunction:
|
||||||
|
if len(args) == 0 {
|
||||||
|
return nil, nil,
|
||||||
|
goerr.Errorf("Missing required argument 'id' for method %v", meth)
|
||||||
|
} else if !args[0].IsString() {
|
||||||
|
return nil, nil,
|
||||||
|
goerr.Errorf("Expected method %v argument 'id' to be a string; got", meth, args[0])
|
||||||
|
}
|
||||||
|
return nil, &SourceQuery{Type: t, GetID: resource.ID(args[0].StringValue())}, nil
|
||||||
|
case specialResourceQueryFunction:
|
||||||
|
contract.Failf("TODO[pulumi/lumi#83]: query not yet implemented")
|
||||||
|
default:
|
||||||
|
contract.Failf("Unrecognized query rendezvous function name: %v", meth.Name())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, transform the object returned into a resource object that the planner can deal with.
|
contract.Failf("Unexpected rendezvous object: %v (expected alloc or query)", obj)
|
||||||
contract.Assert(obj != nil)
|
return nil, nil, nil
|
||||||
info := obj.(*AllocInfo)
|
|
||||||
glog.V(5).Infof("EvalSourceIterator produced a new object: obj=%v, ctx=%v", info.Obj, info.Mod.Tok)
|
|
||||||
return resource.NewObject(info.Obj), info.Mod.Tok, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitEvalConfig applies the configuration map to an existing interpreter context. The map is simply a map of tokens --
|
// InitEvalConfig applies the configuration map to an existing interpreter context. The map is simply a map of tokens --
|
||||||
|
@ -198,8 +236,8 @@ func forkEval(src *evalSource, rz *rendezvous.Rendezvous, e eval.Interpreter) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllocInfo is the context in which an object got allocated.
|
// AllocRendezvous is used when an object is allocated, and tracks the context in which it was allocated.
|
||||||
type AllocInfo struct {
|
type AllocRendezvous struct {
|
||||||
Obj *rt.Object // the object itself.
|
Obj *rt.Object // the object itself.
|
||||||
Loc diag.Diagable // the location information for the allocation.
|
Loc diag.Diagable // the location information for the allocation.
|
||||||
Pkg *symbols.Package // the package being evaluated when the allocation happened.
|
Pkg *symbols.Package // the package being evaluated when the allocation happened.
|
||||||
|
@ -207,6 +245,12 @@ type AllocInfo struct {
|
||||||
Fnc symbols.Function // the function being evaluated when the allocation happened.
|
Fnc symbols.Function // the function being evaluated when the allocation happened.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryRendezvous is used when the interpreter hits a query routine that needs to be evaluated by the planner.
|
||||||
|
type QueryRendezvous struct {
|
||||||
|
Meth *symbols.ClassMethod // the resource method that triggered the need to rendezvous.
|
||||||
|
Args []*rt.Object // the arguments supplied, if any.
|
||||||
|
}
|
||||||
|
|
||||||
// evalHooks are the interpreter hooks that synchronize between planner and evaluator in the appropriate ways.
|
// evalHooks are the interpreter hooks that synchronize between planner and evaluator in the appropriate ways.
|
||||||
type evalHooks struct {
|
type evalHooks struct {
|
||||||
rz *rendezvous.Rendezvous // the rendezvous object.
|
rz *rendezvous.Rendezvous // the rendezvous object.
|
||||||
|
@ -240,7 +284,7 @@ func (h *evalHooks) OnObjectInit(tree diag.Diagable, obj *rt.Object) {
|
||||||
glog.V(9).Infof("EvalSource OnObjectInit %v (IsResource=%v)", obj, resource.IsResourceObject(obj))
|
glog.V(9).Infof("EvalSource OnObjectInit %v (IsResource=%v)", obj, resource.IsResourceObject(obj))
|
||||||
if resource.IsResourceObject(obj) {
|
if resource.IsResourceObject(obj) {
|
||||||
// Communicate the full allocation context: AST node, package, module, and function.
|
// Communicate the full allocation context: AST node, package, module, and function.
|
||||||
alloc := &AllocInfo{
|
alloc := &AllocRendezvous{
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
Loc: tree,
|
Loc: tree,
|
||||||
Pkg: h.currpkg,
|
Pkg: h.currpkg,
|
||||||
|
@ -276,12 +320,39 @@ func (h *evalHooks) OnEnterModule(mod *symbols.Module) func() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnEnterFunction is invoked whenever we enter a new function.
|
const (
|
||||||
func (h *evalHooks) OnEnterFunction(fnc symbols.Function) func() {
|
specialResourceGetFunction = "get" // gets a single resource by ID.
|
||||||
|
specialResourceQueryFunction = "query" // queries 0-to-many resources using arbitrary filters.
|
||||||
|
)
|
||||||
|
|
||||||
|
// OnEnterFunction is invoked whenever we enter a new function. If it returns a non-nil unwind object, it will be used
|
||||||
|
// in place of the actual function call, effectively monkey patching it on the fly.
|
||||||
|
func (h *evalHooks) OnEnterFunction(fnc symbols.Function, args []*rt.Object) (*rt.Unwind, func()) {
|
||||||
glog.V(9).Infof("EvalSource OnEnterFunction %v", fnc)
|
glog.V(9).Infof("EvalSource OnEnterFunction %v", fnc)
|
||||||
prevfnc := h.currfnc
|
prevfnc := h.currfnc
|
||||||
h.currfnc = fnc
|
h.currfnc = fnc
|
||||||
return func() {
|
|
||||||
|
// If this is one of the "special" resource functions, we need to essentially monkey patch it on the fly.
|
||||||
|
var uw *rt.Unwind
|
||||||
|
if meth, ismeth := fnc.(*symbols.ClassMethod); ismeth {
|
||||||
|
if predef.IsResourceType(meth.Parent) {
|
||||||
|
switch meth.Name() {
|
||||||
|
case specialResourceGetFunction, specialResourceQueryFunction:
|
||||||
|
// For any of these functions, we must defer to the planning side to do its thing. After awaiting our
|
||||||
|
// turn, we will be given an opportunity to resume with the object and/or unwind in hand.
|
||||||
|
ret, done, err := h.rz.Meet(evalParty, &QueryRendezvous{
|
||||||
|
Meth: meth,
|
||||||
|
Args: args,
|
||||||
|
})
|
||||||
|
contract.Assertf(ret != nil, "Expecting unwind instructions from the planning goroutine")
|
||||||
|
uw = ret.(*rt.Unwind)
|
||||||
|
contract.Assert(!done)
|
||||||
|
contract.Assert(err == nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uw, func() {
|
||||||
glog.V(9).Infof("EvalSource OnLeaveFunction %v", fnc)
|
glog.V(9).Infof("EvalSource OnLeaveFunction %v", fnc)
|
||||||
h.currfnc = prevfnc
|
h.currfnc = prevfnc
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,10 +56,17 @@ func (iter *fixedSourceIterator) Close() error {
|
||||||
return nil // nothing to do.
|
return nil // nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *fixedSourceIterator) Next() (*resource.Object, tokens.Module, error) {
|
func (iter *fixedSourceIterator) Produce(res *resource.Object) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *fixedSourceIterator) Next() (*SourceAllocation, *SourceQuery, error) {
|
||||||
iter.current++
|
iter.current++
|
||||||
if iter.current >= len(iter.src.resources) {
|
if iter.current >= len(iter.src.resources) {
|
||||||
return nil, "", nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
return iter.src.resources[iter.current], iter.src.ctx, nil
|
return &SourceAllocation{
|
||||||
|
Obj: iter.src.resources[iter.current],
|
||||||
|
Ctx: iter.src.ctx,
|
||||||
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ package deploy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pulumi/lumi/pkg/resource"
|
"github.com/pulumi/lumi/pkg/resource"
|
||||||
"github.com/pulumi/lumi/pkg/tokens"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NullSource is a singleton source that never returns any resources. This may be used in scenarios where the "new"
|
// NullSource is a singleton source that never returns any resources. This may be used in scenarios where the "new"
|
||||||
|
@ -48,6 +47,10 @@ func (iter *nullSourceIterator) Close() error {
|
||||||
return nil // nothing to do.
|
return nil // nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *nullSourceIterator) Next() (*resource.Object, tokens.Module, error) {
|
func (iter *nullSourceIterator) Produce(res *resource.Object) {
|
||||||
return nil, "", nil // means "done"
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *nullSourceIterator) Next() (*SourceAllocation, *SourceQuery, error) {
|
||||||
|
return nil, nil, nil // means "done"
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,191 +16,437 @@
|
||||||
package deploy
|
package deploy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pulumi/lumi/pkg/compiler/symbols"
|
||||||
"github.com/pulumi/lumi/pkg/diag/colors"
|
"github.com/pulumi/lumi/pkg/diag/colors"
|
||||||
"github.com/pulumi/lumi/pkg/resource"
|
"github.com/pulumi/lumi/pkg/resource"
|
||||||
"github.com/pulumi/lumi/pkg/resource/plugin"
|
"github.com/pulumi/lumi/pkg/resource/plugin"
|
||||||
|
"github.com/pulumi/lumi/pkg/tokens"
|
||||||
"github.com/pulumi/lumi/pkg/util/contract"
|
"github.com/pulumi/lumi/pkg/util/contract"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Step is a specification for a deployment operation.
|
// Step is a specification for a deployment operation.
|
||||||
type Step struct {
|
type Step interface {
|
||||||
iter *PlanIterator // the current plan iteration.
|
Op() StepOp // the operation performed by this step.
|
||||||
op StepOp // the operation that will be performed.
|
Plan() *Plan // the owning plan.
|
||||||
urn resource.URN // the resource URN (for before and after).
|
Iterator() *PlanIterator // the current plan iterator.
|
||||||
old *resource.State // the state of the resource before this step.
|
Type() tokens.Type // the type affected by this step.
|
||||||
new *resource.Object // the state of the resource after this step.
|
Pre() error // run any pre-execution steps.
|
||||||
inputs resource.PropertyMap // the input properties to use during the operation.
|
Apply() (resource.Status, error) // applies the action that this step represents.
|
||||||
outputs resource.PropertyMap // the output properties calculated after the operation.
|
Skip() error // skips past this step (required when iterating a plan).
|
||||||
reasons []resource.PropertyKey // the reasons for replacement, if applicable.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSameStep(iter *PlanIterator, old *resource.State, new *resource.Object, inputs resource.PropertyMap) *Step {
|
// ReadStep is a step that doesn't actually modify the target environment. It only reads/queries from it.
|
||||||
|
type ReadStep interface {
|
||||||
|
Step
|
||||||
|
Resources() []*resource.Object // all resource objects returned by this step.
|
||||||
|
}
|
||||||
|
|
||||||
|
// MutatingStep is a step that, when performed, will actually modify/mutate the target environment and its resources.
|
||||||
|
type MutatingStep interface {
|
||||||
|
Step
|
||||||
|
URN() resource.URN // the resource URN (for before and after).
|
||||||
|
New() *resource.Object // the state of the resource before performing this step.
|
||||||
|
Old() *resource.State // the state of the resource after performing this step.
|
||||||
|
Inputs() resource.PropertyMap // the input properties to use during the operation.
|
||||||
|
Outputs() resource.PropertyMap // the output properties calculated during the operation.
|
||||||
|
}
|
||||||
|
|
||||||
|
// SameStep is a mutating step that does nothing.
|
||||||
|
type SameStep struct {
|
||||||
|
iter *PlanIterator // the current plan iteration.
|
||||||
|
old *resource.State // the state of the resource before this step.
|
||||||
|
new *resource.Object // the state of the resource after this step.
|
||||||
|
inputs resource.PropertyMap // the computed inputs supplied at creation time.
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ MutatingStep = (*SameStep)(nil)
|
||||||
|
|
||||||
|
func NewSameStep(iter *PlanIterator, old *resource.State, new *resource.Object, inputs resource.PropertyMap) Step {
|
||||||
contract.Assert(resource.HasURN(old))
|
contract.Assert(resource.HasURN(old))
|
||||||
contract.Assert(!resource.HasURN(new))
|
contract.Assert(!resource.HasURN(new))
|
||||||
return &Step{iter: iter, op: OpSame, urn: old.URN(), old: old, new: new, inputs: inputs}
|
return &SameStep{
|
||||||
}
|
iter: iter,
|
||||||
|
old: old,
|
||||||
func NewCreateStep(iter *PlanIterator, urn resource.URN, new *resource.Object, inputs resource.PropertyMap) *Step {
|
new: new,
|
||||||
contract.Assert(!resource.HasURN(new))
|
inputs: inputs,
|
||||||
return &Step{iter: iter, op: OpCreate, urn: urn, new: new, inputs: inputs}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDeleteStep(iter *PlanIterator, old *resource.State) *Step {
|
|
||||||
contract.Assert(resource.HasURN(old))
|
|
||||||
return &Step{iter: iter, op: OpDelete, urn: old.URN(), old: old}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUpdateStep(iter *PlanIterator, old *resource.State,
|
|
||||||
new *resource.Object, inputs resource.PropertyMap) *Step {
|
|
||||||
contract.Assert(resource.HasURN(old))
|
|
||||||
contract.Assert(!resource.HasURN(new))
|
|
||||||
return &Step{iter: iter, op: OpUpdate, urn: old.URN(), old: old, new: new, inputs: inputs}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewReplaceCreateStep(iter *PlanIterator, old *resource.State,
|
|
||||||
new *resource.Object, inputs resource.PropertyMap, reasons []resource.PropertyKey) *Step {
|
|
||||||
contract.Assert(resource.HasURN(old))
|
|
||||||
contract.Assert(!resource.HasURN(new))
|
|
||||||
return &Step{iter: iter, op: OpReplaceCreate, urn: old.URN(), old: old, new: new, inputs: inputs, reasons: reasons}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewReplaceDeleteStep(iter *PlanIterator, old *resource.State) *Step {
|
|
||||||
contract.Assert(resource.HasURN(old))
|
|
||||||
return &Step{iter: iter, op: OpReplaceDelete, urn: old.URN(), old: old}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Step) Plan() *Plan { return s.iter.p }
|
|
||||||
func (s *Step) Iterator() *PlanIterator { return s.iter }
|
|
||||||
func (s *Step) Op() StepOp { return s.op }
|
|
||||||
func (s *Step) URN() resource.URN { return s.urn }
|
|
||||||
func (s *Step) Old() *resource.State { return s.old }
|
|
||||||
func (s *Step) New() *resource.Object { return s.new }
|
|
||||||
func (s *Step) Inputs() resource.PropertyMap { return s.inputs }
|
|
||||||
func (s *Step) Outputs() resource.PropertyMap { return s.outputs }
|
|
||||||
func (s *Step) Reasons() []resource.PropertyKey { return s.reasons }
|
|
||||||
|
|
||||||
func (s *Step) Provider() (plugin.Provider, error) {
|
|
||||||
contract.Assert(s.old == nil || s.new == nil || s.old.Type() == s.new.Type())
|
|
||||||
if s.old != nil {
|
|
||||||
return s.Plan().Provider(s.old)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SameStep) Op() StepOp { return OpSame }
|
||||||
|
func (s *SameStep) Plan() *Plan { return s.iter.p }
|
||||||
|
func (s *SameStep) Iterator() *PlanIterator { return s.iter }
|
||||||
|
func (s *SameStep) Type() tokens.Type { return s.old.Type() }
|
||||||
|
func (s *SameStep) URN() resource.URN { return s.old.URN() }
|
||||||
|
func (s *SameStep) Old() *resource.State { return s.old }
|
||||||
|
func (s *SameStep) New() *resource.Object { return s.new }
|
||||||
|
func (s *SameStep) Inputs() resource.PropertyMap { return s.inputs }
|
||||||
|
func (s *SameStep) Outputs() resource.PropertyMap { return s.old.Outputs() }
|
||||||
|
|
||||||
|
func (s *SameStep) Pre() error {
|
||||||
|
contract.Assert(s.old != nil)
|
||||||
contract.Assert(s.new != nil)
|
contract.Assert(s.new != nil)
|
||||||
return s.Plan().Provider(s.new)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Step) Apply() (resource.Status, error) {
|
func (s *SameStep) Apply() (resource.Status, error) {
|
||||||
// Fetch the provider.
|
// Just propagate the ID and output state to the live object and append to the snapshot.
|
||||||
prov, err := s.Provider()
|
s.new.Update(s.old.URN(), s.old.ID(), s.old.Outputs())
|
||||||
if err != nil {
|
s.iter.MarkStateSnapshot(s.old)
|
||||||
return resource.StatusOK, err
|
s.iter.AppendStateSnapshot(s.old)
|
||||||
}
|
|
||||||
|
|
||||||
// Now simply perform the operation of the right kind.
|
|
||||||
switch s.op {
|
|
||||||
case OpSame:
|
|
||||||
// Just propagate the ID and output state to the live object and append to the snapshot.
|
|
||||||
contract.Assert(s.old != nil)
|
|
||||||
contract.Assert(s.new != nil)
|
|
||||||
s.new.Update(s.urn, s.old.ID(), s.old.Outputs())
|
|
||||||
s.iter.MarkStateSnapshot(s.old)
|
|
||||||
s.iter.AppendStateSnapshot(s.old)
|
|
||||||
|
|
||||||
case OpCreate, OpReplaceCreate:
|
|
||||||
// Invoke the Create RPC function for this provider:
|
|
||||||
contract.Assert(s.old == nil || s.op == OpReplaceCreate)
|
|
||||||
contract.Assert(s.new != nil)
|
|
||||||
t := s.new.Type()
|
|
||||||
id, rst, err := prov.Create(t, s.inputs)
|
|
||||||
if err != nil {
|
|
||||||
return rst, err
|
|
||||||
}
|
|
||||||
contract.Assert(id != "")
|
|
||||||
|
|
||||||
// Read the resource state back (to fetch outputs) and store everything on the live object.
|
|
||||||
outs, err := prov.Get(t, id)
|
|
||||||
if err != nil {
|
|
||||||
return resource.StatusUnknown, err
|
|
||||||
}
|
|
||||||
s.outputs = outs
|
|
||||||
state := s.new.Update(s.urn, id, outs)
|
|
||||||
if s.old != nil {
|
|
||||||
s.iter.MarkStateSnapshot(s.old)
|
|
||||||
}
|
|
||||||
s.iter.AppendStateSnapshot(state)
|
|
||||||
|
|
||||||
case OpDelete, OpReplaceDelete:
|
|
||||||
// Invoke the Delete RPC function for this provider:
|
|
||||||
contract.Assert(s.old != nil)
|
|
||||||
contract.Assert(s.new == nil)
|
|
||||||
if rst, err := prov.Delete(s.old.Type(), s.old.ID()); err != nil {
|
|
||||||
return rst, err
|
|
||||||
}
|
|
||||||
s.iter.MarkStateSnapshot(s.old)
|
|
||||||
|
|
||||||
case OpUpdate:
|
|
||||||
// Invoke the Update RPC function for this provider:
|
|
||||||
contract.Assert(s.old != nil)
|
|
||||||
contract.Assert(s.new != nil)
|
|
||||||
t := s.old.Type()
|
|
||||||
contract.Assert(t == s.new.Type())
|
|
||||||
id := s.old.ID()
|
|
||||||
contract.Assert(id != "")
|
|
||||||
if rst, err := prov.Update(t, id, s.old.Inputs(), s.inputs); err != nil {
|
|
||||||
return rst, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now read the resource state back in case the update triggered cascading updates to other properties.
|
|
||||||
outs, err := prov.Get(t, id)
|
|
||||||
if err != nil {
|
|
||||||
return resource.StatusUnknown, err
|
|
||||||
}
|
|
||||||
s.outputs = outs
|
|
||||||
state := s.new.Update(s.urn, id, outs)
|
|
||||||
s.iter.MarkStateSnapshot(s.old)
|
|
||||||
s.iter.AppendStateSnapshot(state)
|
|
||||||
|
|
||||||
default:
|
|
||||||
contract.Failf("Unexpected step operation: %v", s.op)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resource.StatusOK, nil
|
return resource.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip skips a step. This is required even when just viewing a plan to ensure in-memory object states are correct.
|
func (s *SameStep) Skip() error {
|
||||||
// This factors in the correct differences in behavior depending on the kind of action being taken.
|
// In the case of a same, both ID and outputs are identical.
|
||||||
func (s *Step) Skip() {
|
s.new.Update(s.old.URN(), s.old.ID(), s.old.Outputs())
|
||||||
switch s.op {
|
return nil
|
||||||
case OpSame:
|
}
|
||||||
// In the case of a same, both ID and outputs are identical.
|
|
||||||
s.new.Update(s.urn, s.old.ID(), s.old.Outputs())
|
// CreateStep is a mutating step that creates an entirely new resource.
|
||||||
case OpCreate:
|
type CreateStep struct {
|
||||||
// In the case of a create, we cannot possibly know the ID or output properties. But we do know the URN.
|
iter *PlanIterator // the current plan iteration.
|
||||||
s.new.SetURN(s.urn)
|
urn resource.URN // the resource URN being created.
|
||||||
case OpUpdate:
|
new *resource.Object // the state of the resource after this step.
|
||||||
// In the case of an update, the ID is the same, however, the outputs remain unknown.
|
inputs resource.PropertyMap // the input properties for the creation.
|
||||||
s.new.SetURN(s.urn)
|
outputs resource.PropertyMap // the output properties after creation.
|
||||||
s.new.SetID(s.old.ID())
|
}
|
||||||
case OpReplaceCreate:
|
|
||||||
// In the case of a replacement, we neither propagate the ID nor output properties. This may be surprising,
|
var _ MutatingStep = (*CreateStep)(nil)
|
||||||
// however, it must be done this way since the entire resource will be deleted and recreated. As a result, we
|
|
||||||
// actually want the ID to be seen as having been updated (triggering cascading updates as appropriate).
|
func NewCreateStep(iter *PlanIterator, urn resource.URN, new *resource.Object, inputs resource.PropertyMap) Step {
|
||||||
case OpDelete, OpReplaceDelete:
|
contract.Assert(!resource.HasURN(new))
|
||||||
// In the case of a deletion, there is no state to propagate: the new object doesn't even exist.
|
return &CreateStep{
|
||||||
default:
|
iter: iter,
|
||||||
contract.Failf("Unexpected step operation: %v", s.op)
|
urn: urn,
|
||||||
|
new: new,
|
||||||
|
inputs: inputs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StepOp represents the kind of operation performed by this step.
|
func (s *CreateStep) Op() StepOp { return OpCreate }
|
||||||
|
func (s *CreateStep) Plan() *Plan { return s.iter.p }
|
||||||
|
func (s *CreateStep) Iterator() *PlanIterator { return s.iter }
|
||||||
|
func (s *CreateStep) Type() tokens.Type { return s.new.Type() }
|
||||||
|
func (s *CreateStep) URN() resource.URN { return s.urn }
|
||||||
|
func (s *CreateStep) Old() *resource.State { return nil }
|
||||||
|
func (s *CreateStep) New() *resource.Object { return s.new }
|
||||||
|
func (s *CreateStep) Inputs() resource.PropertyMap { return s.inputs }
|
||||||
|
func (s *CreateStep) Outputs() resource.PropertyMap { return s.outputs }
|
||||||
|
|
||||||
|
func (s *CreateStep) Pre() error {
|
||||||
|
contract.Assert(s.new != nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CreateStep) Apply() (resource.Status, error) {
|
||||||
|
t := s.new.Type()
|
||||||
|
|
||||||
|
// Invoke the Create RPC function for this provider:
|
||||||
|
prov, err := getProvider(s)
|
||||||
|
if err != nil {
|
||||||
|
return resource.StatusOK, err
|
||||||
|
}
|
||||||
|
id, rst, err := prov.Create(t, s.inputs)
|
||||||
|
if err != nil {
|
||||||
|
return rst, err
|
||||||
|
}
|
||||||
|
contract.Assert(id != "")
|
||||||
|
|
||||||
|
// Read the resource state back (to fetch outputs) and store everything on the live object.
|
||||||
|
outs, err := prov.Get(t, id)
|
||||||
|
if err != nil {
|
||||||
|
return resource.StatusUnknown, err
|
||||||
|
}
|
||||||
|
s.outputs = outs
|
||||||
|
state := s.new.Update(s.urn, id, outs)
|
||||||
|
s.iter.AppendStateSnapshot(state)
|
||||||
|
return resource.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CreateStep) Skip() error {
|
||||||
|
// In the case of a create, we cannot possibly know the ID or output properties. But we do know the URN.
|
||||||
|
s.new.SetURN(s.urn)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteStep is a mutating step that deletes an existing resource.
|
||||||
|
type DeleteStep struct {
|
||||||
|
iter *PlanIterator // the current plan iteration.
|
||||||
|
old *resource.State // the state of the existing resource.
|
||||||
|
replaced bool // true if part of a replacement.
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ MutatingStep = (*DeleteStep)(nil)
|
||||||
|
|
||||||
|
func NewDeleteStep(iter *PlanIterator, old *resource.State, replaced bool) Step {
|
||||||
|
contract.Assert(resource.HasURN(old))
|
||||||
|
return &DeleteStep{
|
||||||
|
iter: iter,
|
||||||
|
old: old,
|
||||||
|
replaced: replaced,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DeleteStep) Op() StepOp { return OpDelete }
|
||||||
|
func (s *DeleteStep) Plan() *Plan { return s.iter.p }
|
||||||
|
func (s *DeleteStep) Iterator() *PlanIterator { return s.iter }
|
||||||
|
func (s *DeleteStep) Type() tokens.Type { return s.old.Type() }
|
||||||
|
func (s *DeleteStep) URN() resource.URN { return s.old.URN() }
|
||||||
|
func (s *DeleteStep) Old() *resource.State { return s.old }
|
||||||
|
func (s *DeleteStep) New() *resource.Object { return nil }
|
||||||
|
func (s *DeleteStep) Inputs() resource.PropertyMap { return s.old.Inputs() }
|
||||||
|
func (s *DeleteStep) Outputs() resource.PropertyMap { return s.old.Outputs() }
|
||||||
|
func (s *DeleteStep) Replaced() bool { return s.replaced }
|
||||||
|
|
||||||
|
func (s *DeleteStep) Pre() error {
|
||||||
|
contract.Assert(s.old != nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DeleteStep) Apply() (resource.Status, error) {
|
||||||
|
// Invoke the Delete RPC function for this provider:
|
||||||
|
prov, err := getProvider(s)
|
||||||
|
if err != nil {
|
||||||
|
return resource.StatusOK, err
|
||||||
|
}
|
||||||
|
if rst, err := prov.Delete(s.old.Type(), s.old.ID()); err != nil {
|
||||||
|
return rst, err
|
||||||
|
}
|
||||||
|
s.iter.MarkStateSnapshot(s.old)
|
||||||
|
return resource.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DeleteStep) Skip() error {
|
||||||
|
// In the case of a deletion, there is no state to propagate: the new object doesn't even exist.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateStep is a mutating step that updates an existing resource's state.
|
||||||
|
type UpdateStep struct {
|
||||||
|
iter *PlanIterator // the current plan iteration.
|
||||||
|
old *resource.State // the state of the existing resource.
|
||||||
|
new *resource.Object // the live resource object.
|
||||||
|
inputs resource.PropertyMap // the input properties for the update.
|
||||||
|
outputs resource.PropertyMap // the output properties populated after updating.
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ MutatingStep = (*UpdateStep)(nil)
|
||||||
|
|
||||||
|
func NewUpdateStep(iter *PlanIterator, old *resource.State,
|
||||||
|
new *resource.Object, inputs resource.PropertyMap) Step {
|
||||||
|
contract.Assert(resource.HasURN(old))
|
||||||
|
contract.Assert(!resource.HasURN(new))
|
||||||
|
return &UpdateStep{
|
||||||
|
iter: iter,
|
||||||
|
old: old,
|
||||||
|
new: new,
|
||||||
|
inputs: inputs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UpdateStep) Op() StepOp { return OpUpdate }
|
||||||
|
func (s *UpdateStep) Plan() *Plan { return s.iter.p }
|
||||||
|
func (s *UpdateStep) Iterator() *PlanIterator { return s.iter }
|
||||||
|
func (s *UpdateStep) Type() tokens.Type { return s.old.Type() }
|
||||||
|
func (s *UpdateStep) URN() resource.URN { return s.old.URN() }
|
||||||
|
func (s *UpdateStep) Old() *resource.State { return s.old }
|
||||||
|
func (s *UpdateStep) New() *resource.Object { return s.new }
|
||||||
|
func (s *UpdateStep) Inputs() resource.PropertyMap { return s.inputs }
|
||||||
|
func (s *UpdateStep) Outputs() resource.PropertyMap { return s.outputs }
|
||||||
|
|
||||||
|
func (s *UpdateStep) Pre() error {
|
||||||
|
contract.Assert(s.old != nil)
|
||||||
|
contract.Assert(s.new != nil)
|
||||||
|
contract.Assert(s.old.Type() == s.new.Type())
|
||||||
|
contract.Assert(s.old.ID() != "")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UpdateStep) Apply() (resource.Status, error) {
|
||||||
|
t := s.old.Type()
|
||||||
|
id := s.old.ID()
|
||||||
|
|
||||||
|
// Invoke the Update RPC function for this provider:
|
||||||
|
prov, err := getProvider(s)
|
||||||
|
if err != nil {
|
||||||
|
return resource.StatusOK, err
|
||||||
|
}
|
||||||
|
if rst, err := prov.Update(t, id, s.old.Inputs(), s.inputs); err != nil {
|
||||||
|
return rst, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now read the resource state back in case the update triggered cascading updates to other properties.
|
||||||
|
outs, err := prov.Get(t, id)
|
||||||
|
if err != nil {
|
||||||
|
return resource.StatusUnknown, err
|
||||||
|
}
|
||||||
|
s.outputs = outs
|
||||||
|
state := s.new.Update(s.old.URN(), id, outs)
|
||||||
|
s.iter.MarkStateSnapshot(s.old)
|
||||||
|
s.iter.AppendStateSnapshot(state)
|
||||||
|
return resource.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UpdateStep) Skip() error {
|
||||||
|
// In the case of an update, the ID is the same, however, the outputs remain unknown.
|
||||||
|
s.new.SetURN(s.old.URN())
|
||||||
|
s.new.SetID(s.old.ID())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplaceStep is a mutating step that updates an existing resource's state.
|
||||||
|
type ReplaceStep struct {
|
||||||
|
iter *PlanIterator // the current plan iteration.
|
||||||
|
old *resource.State // the state of the existing resource.
|
||||||
|
new *resource.Object // the live resource object.
|
||||||
|
inputs resource.PropertyMap // the input properties for the replacement.
|
||||||
|
outputs resource.PropertyMap // the output properties populated after replacing.
|
||||||
|
reasons []resource.PropertyKey // the reasons for the replacement.
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReplaceStep(iter *PlanIterator, old *resource.State,
|
||||||
|
new *resource.Object, inputs resource.PropertyMap, reasons []resource.PropertyKey) Step {
|
||||||
|
contract.Assert(resource.HasURN(old))
|
||||||
|
contract.Assert(!resource.HasURN(new))
|
||||||
|
return &ReplaceStep{
|
||||||
|
iter: iter,
|
||||||
|
old: old,
|
||||||
|
new: new,
|
||||||
|
inputs: inputs,
|
||||||
|
reasons: reasons,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReplaceStep) Op() StepOp { return OpReplace }
|
||||||
|
func (s *ReplaceStep) Plan() *Plan { return s.iter.p }
|
||||||
|
func (s *ReplaceStep) Iterator() *PlanIterator { return s.iter }
|
||||||
|
func (s *ReplaceStep) Type() tokens.Type { return s.old.Type() }
|
||||||
|
func (s *ReplaceStep) URN() resource.URN { return s.old.URN() }
|
||||||
|
func (s *ReplaceStep) Old() *resource.State { return s.old }
|
||||||
|
func (s *ReplaceStep) New() *resource.Object { return s.new }
|
||||||
|
func (s *ReplaceStep) Inputs() resource.PropertyMap { return s.inputs }
|
||||||
|
func (s *ReplaceStep) Outputs() resource.PropertyMap { return s.outputs }
|
||||||
|
func (s *ReplaceStep) Reasons() []resource.PropertyKey { return s.reasons }
|
||||||
|
|
||||||
|
func (s *ReplaceStep) Pre() error {
|
||||||
|
contract.Assert(s.old != nil)
|
||||||
|
contract.Assert(s.new != nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReplaceStep) Apply() (resource.Status, error) {
|
||||||
|
t := s.new.Type()
|
||||||
|
|
||||||
|
// Invoke the Create RPC function for this provider:
|
||||||
|
prov, err := getProvider(s)
|
||||||
|
if err != nil {
|
||||||
|
return resource.StatusOK, err
|
||||||
|
}
|
||||||
|
id, rst, err := prov.Create(t, s.inputs)
|
||||||
|
if err != nil {
|
||||||
|
return rst, err
|
||||||
|
}
|
||||||
|
contract.Assert(id != "")
|
||||||
|
|
||||||
|
// Read the resource state back (to fetch outputs) and store everything on the live object.
|
||||||
|
outs, err := prov.Get(t, id)
|
||||||
|
if err != nil {
|
||||||
|
return resource.StatusUnknown, err
|
||||||
|
}
|
||||||
|
s.outputs = outs
|
||||||
|
state := s.new.Update(s.old.URN(), id, outs)
|
||||||
|
s.iter.MarkStateSnapshot(s.old)
|
||||||
|
s.iter.AppendStateSnapshot(state)
|
||||||
|
return resource.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReplaceStep) Skip() error {
|
||||||
|
// In the case of a replacement, we neither propagate the ID nor output properties. This may be surprising,
|
||||||
|
// however, it must be done this way since the entire resource will be deleted and recreated. As a result, we
|
||||||
|
// actually want the ID to be seen as having been updated (triggering cascading updates as appropriate).
|
||||||
|
s.new.SetURN(s.old.URN())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStep is a read-only step that queries for a single resource.
|
||||||
|
type GetStep struct {
|
||||||
|
iter *PlanIterator // the current plan iteration.
|
||||||
|
t symbols.Type // the type of resource to query.
|
||||||
|
id resource.ID // the ID of the resource being sought.
|
||||||
|
obj *resource.Object // the resource object read back from this operation.
|
||||||
|
outputs resource.PropertyMap // the output properties populated after updating.
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ ReadStep = (*GetStep)(nil)
|
||||||
|
|
||||||
|
func NewGetStep(iter *PlanIterator, t symbols.Type, id resource.ID, obj *resource.Object) Step {
|
||||||
|
return &GetStep{
|
||||||
|
iter: iter,
|
||||||
|
t: t,
|
||||||
|
id: id,
|
||||||
|
obj: obj,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GetStep) Op() StepOp { return OpGet }
|
||||||
|
func (s *GetStep) Plan() *Plan { return s.iter.p }
|
||||||
|
func (s *GetStep) Iterator() *PlanIterator { return s.iter }
|
||||||
|
func (s *GetStep) Type() tokens.Type { return s.t.TypeToken() }
|
||||||
|
func (s *GetStep) Resources() []*resource.Object { return []*resource.Object{s.obj} }
|
||||||
|
|
||||||
|
func (s *GetStep) Pre() error {
|
||||||
|
// Simply call through to the provider's Get API.
|
||||||
|
id := s.id
|
||||||
|
prov, err := getProvider(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outs, err := prov.Get(s.Type(), id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.outputs = outs
|
||||||
|
|
||||||
|
// If no pre-existing object was supplied, create a new one.
|
||||||
|
if s.obj == nil {
|
||||||
|
s.obj = resource.NewEmptyObject(s.t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the object's ID, properties, and URN with the state we read back.
|
||||||
|
// TODO: it's not clear yet how to correctly populate the URN, given that the allocation context is unknown.
|
||||||
|
s.obj.SetID(id)
|
||||||
|
s.obj.SetProperties(outs)
|
||||||
|
|
||||||
|
// Finally, the iterate must communicate the result back to the interpreter, by way of an unwind.
|
||||||
|
s.iter.Produce(s.obj)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GetStep) Apply() (resource.Status, error) {
|
||||||
|
return resource.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GetStep) Skip() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getProvider fetches the provider for the given step.
|
||||||
|
func getProvider(s Step) (plugin.Provider, error) {
|
||||||
|
return s.Plan().ProviderT(s.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
// StepOp represents the kind of operation performed by a step. It evaluates to its string label.
|
||||||
type StepOp string
|
type StepOp string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OpSame StepOp = "same" // nothing to do.
|
OpSame StepOp = "same" // nothing to do.
|
||||||
OpCreate StepOp = "create" // creating a new resource.
|
OpCreate StepOp = "create" // creating a new resource.
|
||||||
OpUpdate StepOp = "update" // updating an existing resource.
|
OpUpdate StepOp = "update" // updating an existing resource.
|
||||||
OpDelete StepOp = "delete" // deleting an existing resource.
|
OpDelete StepOp = "delete" // deleting an existing resource.
|
||||||
OpReplaceCreate StepOp = "replace" // replacing a resource with a new one.
|
OpReplace StepOp = "replace" // replacing a resource with a new one.
|
||||||
OpReplaceDelete StepOp = "replace-delete" // the fine-grained replacement step to delete the old resource.
|
OpGet StepOp = "get" // fetching a resource by ID or URN.
|
||||||
|
OpQuery StepOp = "query" // querying a resource list by type and filter.
|
||||||
)
|
)
|
||||||
|
|
||||||
// StepOps contains the full set of step operation types.
|
// StepOps contains the full set of step operation types.
|
||||||
|
@ -209,8 +455,9 @@ var StepOps = []StepOp{
|
||||||
OpCreate,
|
OpCreate,
|
||||||
OpUpdate,
|
OpUpdate,
|
||||||
OpDelete,
|
OpDelete,
|
||||||
OpReplaceCreate,
|
OpReplace,
|
||||||
OpReplaceDelete,
|
OpGet,
|
||||||
|
OpQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color returns a suggested color for lines of this op type.
|
// Color returns a suggested color for lines of this op type.
|
||||||
|
@ -224,10 +471,10 @@ func (op StepOp) Color() string {
|
||||||
return colors.SpecDeleted
|
return colors.SpecDeleted
|
||||||
case OpUpdate:
|
case OpUpdate:
|
||||||
return colors.SpecChanged
|
return colors.SpecChanged
|
||||||
case OpReplaceCreate:
|
case OpReplace:
|
||||||
return colors.SpecReplaced
|
return colors.SpecReplaced
|
||||||
case OpReplaceDelete:
|
case OpGet, OpQuery:
|
||||||
return colors.SpecDeleted
|
return colors.SpecRead
|
||||||
default:
|
default:
|
||||||
contract.Failf("Unrecognized resource step op: %v", op)
|
contract.Failf("Unrecognized resource step op: %v", op)
|
||||||
return ""
|
return ""
|
||||||
|
@ -237,18 +484,16 @@ func (op StepOp) Color() string {
|
||||||
// Prefix returns a suggested prefix for lines of this op type.
|
// Prefix returns a suggested prefix for lines of this op type.
|
||||||
func (op StepOp) Prefix() string {
|
func (op StepOp) Prefix() string {
|
||||||
switch op {
|
switch op {
|
||||||
case OpSame:
|
case OpSame, OpGet, OpQuery:
|
||||||
return op.Color() + " "
|
return op.Color() + " "
|
||||||
case OpCreate:
|
case OpCreate:
|
||||||
return op.Color() + "+ "
|
return op.Color() + "+ "
|
||||||
case OpDelete:
|
case OpDelete:
|
||||||
return op.Color() + "- "
|
return op.Color() + "- "
|
||||||
case OpUpdate:
|
case OpUpdate:
|
||||||
return op.Color() + " "
|
return op.Color() + "~ "
|
||||||
case OpReplaceCreate:
|
case OpReplace:
|
||||||
return op.Color() + "~+"
|
return op.Color() + "+-"
|
||||||
case OpReplaceDelete:
|
|
||||||
return op.Color() + "~-"
|
|
||||||
default:
|
default:
|
||||||
contract.Failf("Unrecognized resource step op: %v", op)
|
contract.Failf("Unrecognized resource step op: %v", op)
|
||||||
return ""
|
return ""
|
||||||
|
@ -257,8 +502,8 @@ func (op StepOp) Prefix() string {
|
||||||
|
|
||||||
// Suffix returns a suggested suffix for lines of this op type.
|
// Suffix returns a suggested suffix for lines of this op type.
|
||||||
func (op StepOp) Suffix() string {
|
func (op StepOp) Suffix() string {
|
||||||
if op == OpUpdate || op == OpReplaceCreate {
|
if op == OpUpdate || op == OpReplace || op == OpGet {
|
||||||
return colors.Reset // updates and replacements colorize individual lines
|
return colors.Reset // updates and replacements colorize individual lines; get has none
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,14 @@ func NewObject(obj *rt.Object) *Object {
|
||||||
return &Object{obj: obj}
|
return &Object{obj: obj}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEmptyObject allocates an empty resource object of a given type.
|
||||||
|
func NewEmptyObject(t symbols.Type) *Object {
|
||||||
|
contract.Assert(predef.IsResourceType(t))
|
||||||
|
return &Object{
|
||||||
|
obj: rt.NewObject(t, nil, nil, nil),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Object) Obj() *rt.Object { return r.obj }
|
func (r *Object) Obj() *rt.Object { return r.obj }
|
||||||
func (r *Object) Type() tokens.Type { return r.obj.Type().TypeToken() }
|
func (r *Object) Type() tokens.Type { return r.obj.Type().TypeToken() }
|
||||||
|
|
||||||
|
|
|
@ -316,6 +316,7 @@ func (g *PackGenerator) emitResourceClass(w *bufio.Writer, res *Resource) {
|
||||||
} else {
|
} else {
|
||||||
writefmtln(w, " super();")
|
writefmtln(w, " super();")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, validate that required parameters exist, and store all arguments on the object.
|
// Next, validate that required parameters exist, and store all arguments on the object.
|
||||||
argLinePrefix := " "
|
argLinePrefix := " "
|
||||||
needsArgsCheck := hasArgs && !hasRequiredArgs
|
needsArgsCheck := hasArgs && !hasRequiredArgs
|
||||||
|
@ -338,6 +339,17 @@ func (g *PackGenerator) emitResourceClass(w *bufio.Writer, res *Resource) {
|
||||||
}
|
}
|
||||||
|
|
||||||
writefmtln(w, " }")
|
writefmtln(w, " }")
|
||||||
|
writefmtln(w, "")
|
||||||
|
|
||||||
|
// Finally, add the standard "factory" functions: get and query.
|
||||||
|
writefmtln(w, " public static get(id: lumi.ID): %v {", name)
|
||||||
|
writefmtln(w, " return <any>undefined; // functionality provided by the runtime")
|
||||||
|
writefmtln(w, " }")
|
||||||
|
writefmtln(w, "")
|
||||||
|
writefmtln(w, " public static query(q: any): %v[] {", name)
|
||||||
|
writefmtln(w, " return <any>undefined; // functionality provided by the runtime")
|
||||||
|
writefmtln(w, " }")
|
||||||
|
|
||||||
writefmtln(w, "}")
|
writefmtln(w, "}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue