2018-05-22 21:43:36 +02:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
|
|
|
package deploy
|
|
|
|
|
|
|
|
import (
|
2017-09-09 16:37:10 +02:00
|
|
|
"fmt"
|
2017-08-30 03:24:12 +02:00
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
pbempty "github.com/golang/protobuf/ptypes/empty"
|
2017-08-30 03:24:12 +02:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"golang.org/x/net/context"
|
|
|
|
"google.golang.org/grpc"
|
2018-05-17 00:37:34 +02:00
|
|
|
"google.golang.org/grpc/codes"
|
2017-08-30 03:24:12 +02:00
|
|
|
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
|
|
|
"github.com/pulumi/pulumi/pkg/resource/plugin"
|
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
2018-05-16 00:28:00 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/logging"
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/rpcutil"
|
2018-05-17 00:37:34 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/rpcutil/rpcerror"
|
2018-02-14 22:56:16 +01:00
|
|
|
"github.com/pulumi/pulumi/pkg/workspace"
|
2018-04-05 18:48:09 +02:00
|
|
|
pulumirpc "github.com/pulumi/pulumi/sdk/proto/go"
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
)
|
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// EvalRunInfo provides information required to execute and deploy resources within a package.
|
|
|
|
type EvalRunInfo struct {
|
2018-02-14 22:56:16 +01:00
|
|
|
Proj *workspace.Project `json:"proj" yaml:"proj"` // the package metadata.
|
|
|
|
Pwd string `json:"pwd" yaml:"pwd"` // the package's working directory.
|
|
|
|
Program string `json:"program" yaml:"program"` // the path to the program.
|
|
|
|
Args []string `json:"args,omitempty" yaml:"args,omitempty"` // any arguments to pass to the package.
|
|
|
|
Target *Target `json:"target,omitempty" yaml:"target,omitempty"` // the target being deployed into.
|
2017-08-30 03:24:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewEvalSource returns a planning source that fetches resources by evaluating a package with a set of args and
|
|
|
|
// a confgiuration map. This evaluation is performed using the given plugin context and may optionally use the
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
// given plugin host (or the default, if this is nil). Note that closing the eval source also closes the host.
|
General prep work for refresh
This change includes a bunch of refactorings I made in prep for
doing refresh (first, the command, see pulumi/pulumi#1081):
* The primary change is to change the way the engine's core update
functionality works with respect to deploy.Source. This is the
way we can plug in new sources of resource information during
planning (and, soon, diffing). The way I intend to model refresh
is by having a new kind of source, deploy.RefreshSource, which
will let us do virtually everything about an update/diff the same
way with refreshes, which avoid otherwise duplicative effort.
This includes changing the planOptions (nee deployOptions) to
take a new SourceFunc callback, which is responsible for creating
a source specific to the kind of plan being requested.
Preview, Update, and Destroy now are primarily differentiated by
the kind of deploy.Source that they return, rather than sprinkling
things like `if Destroying` throughout. This tidies up some logic
and, more importantly, gives us precisely the refresh hook we need.
* Originally, we used the deploy.NullSource for Destroy operations.
This simply returns nothing, which is how Destroy works. For some
reason, we were no longer doing this, and instead had some
`if Destroying` cases sprinkled throughout the deploy.EvalSource.
I think this is a vestige of some old way we did configuration, at
least judging by a comment, which is apparently no longer relevant.
* Move diff and diff-printing logic within the engine into its own
pkg/engine/diff.go file, to prepare for upcoming work.
* I keep noticing benign diffs anytime I regenerate protobufs. I
suspect this is because we're also on different versions. I changed
generate.sh to also dump the version into grpc_version.txt. At
least we can understand where the diffs are coming from, decide
whether to take them (i.e., a newer version), and ensure that as
a team we are monotonically increasing, and not going backwards.
* I also tidied up some tiny things I noticed while in there, like
comments, incorrect types, lint suppressions, and so on.
2018-03-28 16:45:23 +02:00
|
|
|
func NewEvalSource(plugctx *plugin.Context, runinfo *EvalRunInfo, dryRun bool) Source {
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
return &evalSource{
|
2017-06-21 19:31:06 +02:00
|
|
|
plugctx: plugctx,
|
2017-08-30 03:24:12 +02:00
|
|
|
runinfo: runinfo,
|
|
|
|
dryRun: dryRun,
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type evalSource struct {
|
2017-08-30 03:24:12 +02:00
|
|
|
plugctx *plugin.Context // the plugin context.
|
|
|
|
runinfo *EvalRunInfo // the directives to use when running the program.
|
|
|
|
dryRun bool // true if this is a dry-run operation only.
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (src *evalSource) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-04-05 18:48:09 +02:00
|
|
|
// Project is the name of the project being run by this evaluation source.
|
2018-02-14 22:56:16 +01:00
|
|
|
func (src *evalSource) Project() tokens.PackageName {
|
|
|
|
return src.runinfo.Proj.Name
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
2018-04-05 18:48:09 +02:00
|
|
|
// Stack is the name of the stack being targeted by this evaluation source.
|
|
|
|
func (src *evalSource) Stack() tokens.QName {
|
|
|
|
return src.runinfo.Target.Name
|
|
|
|
}
|
|
|
|
|
Implement a refresh command
This change implements a `pulumi refresh` command. It operates a bit
like `pulumi update`, and friends, in that it supports `--preview` and
`--diff`, along with the usual flags, and will update your checkpoint.
It works through substitution of the deploy.Source abstraction, which
generates a sequence of resource registration events. This new
deploy.RefreshSource takes in a prior checkpoint and will walk it,
refreshing the state via the associated resource providers by invoking
Read for each resource encountered, and merging the resulting state with
the prior checkpoint, to yield a new resource.Goal state. This state is
then fed through the engine in the usual ways with a few minor caveats:
namely, although the engine must generate steps for the logical
operations (permitting us to get nice summaries, progress, and diffs),
it mustn't actually carry them out because the state being imported
already reflects reality (a deleted resource has *already* been deleted,
so of course the engine need not perform the deletion). The diffing
logic also needs to know how to treat the case of refresh slightly
differently, because we are going to be diffing outputs and not inputs.
Note that support for managed stacks is not yet complete, since that
requires updates to the service to support a refresh endpoint. That
will be coming soon ...
2018-04-10 20:22:39 +02:00
|
|
|
func (src *evalSource) Info() interface{} { return src.runinfo }
|
2018-04-18 20:12:02 +02:00
|
|
|
func (src *evalSource) IsRefresh() bool { return false }
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
|
|
|
// Iterate will spawn an evaluator coroutine and prepare to interact with it on subsequent calls to Next.
|
2017-09-16 01:38:52 +02:00
|
|
|
func (src *evalSource) Iterate(opts Options) (SourceIterator, error) {
|
2017-08-30 03:24:12 +02:00
|
|
|
// First, fire up a resource monitor that will watch for and record resource creation.
|
2017-11-29 20:27:32 +01:00
|
|
|
regChan := make(chan *registerResourceEvent)
|
|
|
|
regOutChan := make(chan *registerResourceOutputsEvent)
|
|
|
|
mon, err := newResourceMonitor(src, regChan, regOutChan)
|
2017-08-30 03:24:12 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "failed to start resource monitor")
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Create a new iterator with appropriate channels, and gear up to go!
|
|
|
|
iter := &evalSourceIterator{
|
2017-11-29 20:27:32 +01:00
|
|
|
mon: mon,
|
|
|
|
src: src,
|
|
|
|
regChan: regChan,
|
|
|
|
regOutChan: regOutChan,
|
|
|
|
finChan: make(chan error),
|
2017-06-22 07:02:57 +02:00
|
|
|
}
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Now invoke Run in a goroutine. All subsequent resource creation events will come in over the gRPC channel,
|
|
|
|
// and we will pump them through the channel. If the Run call ultimately fails, we need to propagate the error.
|
2017-09-16 01:38:52 +02:00
|
|
|
iter.forkRun(opts)
|
2017-08-30 03:24:12 +02:00
|
|
|
|
|
|
|
// Finally, return the fresh iterator that the caller can use to take things from here.
|
|
|
|
return iter, nil
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type evalSourceIterator struct {
|
2017-11-29 20:27:32 +01:00
|
|
|
mon *resmon // the resource monitor, per iterator.
|
|
|
|
src *evalSource // the owning eval source object.
|
|
|
|
regChan chan *registerResourceEvent // the channel that contains resource registrations.
|
|
|
|
regOutChan chan *registerResourceOutputsEvent // the channel that contains resource completions.
|
|
|
|
finChan chan error // the channel that communicates completion.
|
|
|
|
done bool // set to true when the evaluation is done.
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (iter *evalSourceIterator) Close() error {
|
2017-09-09 00:11:09 +02:00
|
|
|
// Cancel the monitor and reclaim any associated resources.
|
|
|
|
return iter.mon.Cancel()
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
Bring back component outputs
This change brings back component outputs to the overall system again.
In doing so, it generally overhauls the way we do resource RPCs a bit:
* Instead of RegisterResource and CompleteResource, we call these
BeginRegisterResource and EndRegisterResource, which begins to model
these as effectively "asynchronous" resource requests. This should also
help with parallelism (https://github.com/pulumi/pulumi/issues/106).
* Flip the CLI/engine a little on its head. Rather than it driving the
planning and deployment process, we move more to a model where it
simply observes it. This is done by implementing an event handler
interface with three events: OnResourceStepPre, OnResourceStepPost,
and OnResourceComplete. The first two are invoked immediately before
and after any step operation, and the latter is invoked whenever a
EndRegisterResource comes in. The reason for the asymmetry here is
that the checkpointing logic in the deployment engine is largely
untouched (intentionally, as this is a sensitive part of the system),
and so the "begin"/"end" nature doesn't flow through faithfully.
* Also make the engine more event-oriented in its terminology and the
way it handles the incoming BeginRegisterResource and
EndRegisterResource events from the language host. This is the first
step down a long road of incrementally refactoring the engine to work
this way, a necessary prerequisite for parallelism.
2017-11-29 16:42:14 +01:00
|
|
|
func (iter *evalSourceIterator) Next() (SourceEvent, error) {
|
2017-08-30 03:24:12 +02:00
|
|
|
// If we are done, quit.
|
|
|
|
if iter.done {
|
|
|
|
return nil, nil
|
|
|
|
}
|
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).
2017-06-20 02:24:00 +02:00
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Await the program to compute some more state and then inspect what it has to say.
|
|
|
|
select {
|
2017-11-21 02:38:09 +01:00
|
|
|
case reg := <-iter.regChan:
|
|
|
|
contract.Assert(reg != nil)
|
|
|
|
goal := reg.Goal()
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof("EvalSourceIterator produced a registration: t=%v,name=%v,#props=%v",
|
2017-11-21 02:38:09 +01:00
|
|
|
goal.Type, goal.Name, len(goal.Properties))
|
|
|
|
return reg, nil
|
2017-11-29 20:27:32 +01:00
|
|
|
case regOut := <-iter.regOutChan:
|
|
|
|
contract.Assert(regOut != nil)
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof("EvalSourceIterator produced a completion: urn=%v,#outs=%v",
|
2017-11-29 20:27:32 +01:00
|
|
|
regOut.URN(), len(regOut.Outputs()))
|
|
|
|
return regOut, nil
|
2017-11-21 02:38:09 +01:00
|
|
|
case err := <-iter.finChan:
|
2017-08-30 03:24:12 +02:00
|
|
|
// If we are finished, we can safely exit. The contract with the language provider is that this implies
|
|
|
|
// that the language runtime has exited and so calling Close on the plugin is fine.
|
|
|
|
iter.done = true
|
|
|
|
if err != nil {
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof("EvalSourceIterator ended with an error: %v", err)
|
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).
2017-06-20 02:24:00 +02:00
|
|
|
}
|
2017-08-30 03:24:12 +02:00
|
|
|
return nil, err
|
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).
2017-06-20 02:24:00 +02:00
|
|
|
}
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// forkRun performs the evaluation from a distinct goroutine. This function blocks until it's our turn to go.
|
2017-09-16 01:38:52 +02:00
|
|
|
func (iter *evalSourceIterator) forkRun(opts Options) {
|
General prep work for refresh
This change includes a bunch of refactorings I made in prep for
doing refresh (first, the command, see pulumi/pulumi#1081):
* The primary change is to change the way the engine's core update
functionality works with respect to deploy.Source. This is the
way we can plug in new sources of resource information during
planning (and, soon, diffing). The way I intend to model refresh
is by having a new kind of source, deploy.RefreshSource, which
will let us do virtually everything about an update/diff the same
way with refreshes, which avoid otherwise duplicative effort.
This includes changing the planOptions (nee deployOptions) to
take a new SourceFunc callback, which is responsible for creating
a source specific to the kind of plan being requested.
Preview, Update, and Destroy now are primarily differentiated by
the kind of deploy.Source that they return, rather than sprinkling
things like `if Destroying` throughout. This tidies up some logic
and, more importantly, gives us precisely the refresh hook we need.
* Originally, we used the deploy.NullSource for Destroy operations.
This simply returns nothing, which is how Destroy works. For some
reason, we were no longer doing this, and instead had some
`if Destroying` cases sprinkled throughout the deploy.EvalSource.
I think this is a vestige of some old way we did configuration, at
least judging by a comment, which is apparently no longer relevant.
* Move diff and diff-printing logic within the engine into its own
pkg/engine/diff.go file, to prepare for upcoming work.
* I keep noticing benign diffs anytime I regenerate protobufs. I
suspect this is because we're also on different versions. I changed
generate.sh to also dump the version into grpc_version.txt. At
least we can understand where the diffs are coming from, decide
whether to take them (i.e., a newer version), and ensure that as
a team we are monotonically increasing, and not going backwards.
* I also tidied up some tiny things I noticed while in there, like
comments, incorrect types, lint suppressions, and so on.
2018-03-28 16:45:23 +02:00
|
|
|
// Fire up the goroutine to make the RPC invocation against the language runtime. As this executes, calls
|
|
|
|
// to queue things up in the resource channel will occur, and we will serve them concurrently.
|
|
|
|
go func() {
|
|
|
|
// Next, launch the language plugin.
|
|
|
|
run := func() error {
|
|
|
|
rt := iter.src.runinfo.Proj.Runtime
|
|
|
|
langhost, err := iter.src.plugctx.Host.LanguageRuntime(rt)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "failed to launch language host %s", rt)
|
|
|
|
}
|
|
|
|
contract.Assertf(langhost != nil, "expected non-nil language host %s", rt)
|
|
|
|
|
|
|
|
// Make sure to clean up before exiting.
|
|
|
|
defer contract.IgnoreClose(langhost)
|
|
|
|
|
|
|
|
// Decrypt the configuration.
|
|
|
|
config, err := iter.src.runinfo.Target.Config.Decrypt(iter.src.runinfo.Target.Decrypter)
|
|
|
|
if err != nil {
|
2017-12-05 02:10:40 +01:00
|
|
|
return err
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
2017-09-09 00:11:09 +02:00
|
|
|
|
General prep work for refresh
This change includes a bunch of refactorings I made in prep for
doing refresh (first, the command, see pulumi/pulumi#1081):
* The primary change is to change the way the engine's core update
functionality works with respect to deploy.Source. This is the
way we can plug in new sources of resource information during
planning (and, soon, diffing). The way I intend to model refresh
is by having a new kind of source, deploy.RefreshSource, which
will let us do virtually everything about an update/diff the same
way with refreshes, which avoid otherwise duplicative effort.
This includes changing the planOptions (nee deployOptions) to
take a new SourceFunc callback, which is responsible for creating
a source specific to the kind of plan being requested.
Preview, Update, and Destroy now are primarily differentiated by
the kind of deploy.Source that they return, rather than sprinkling
things like `if Destroying` throughout. This tidies up some logic
and, more importantly, gives us precisely the refresh hook we need.
* Originally, we used the deploy.NullSource for Destroy operations.
This simply returns nothing, which is how Destroy works. For some
reason, we were no longer doing this, and instead had some
`if Destroying` cases sprinkled throughout the deploy.EvalSource.
I think this is a vestige of some old way we did configuration, at
least judging by a comment, which is apparently no longer relevant.
* Move diff and diff-printing logic within the engine into its own
pkg/engine/diff.go file, to prepare for upcoming work.
* I keep noticing benign diffs anytime I regenerate protobufs. I
suspect this is because we're also on different versions. I changed
generate.sh to also dump the version into grpc_version.txt. At
least we can understand where the diffs are coming from, decide
whether to take them (i.e., a newer version), and ensure that as
a team we are monotonically increasing, and not going backwards.
* I also tidied up some tiny things I noticed while in there, like
comments, incorrect types, lint suppressions, and so on.
2018-03-28 16:45:23 +02:00
|
|
|
// Now run the actual program.
|
|
|
|
var progerr string
|
|
|
|
progerr, err = langhost.Run(plugin.RunInfo{
|
|
|
|
MonitorAddress: iter.mon.Address(),
|
|
|
|
Stack: string(iter.src.runinfo.Target.Name),
|
|
|
|
Project: string(iter.src.runinfo.Proj.Name),
|
|
|
|
Pwd: iter.src.runinfo.Pwd,
|
|
|
|
Program: iter.src.runinfo.Program,
|
|
|
|
Args: iter.src.runinfo.Args,
|
|
|
|
Config: config,
|
|
|
|
DryRun: iter.src.dryRun,
|
|
|
|
Parallel: opts.Parallel,
|
|
|
|
})
|
|
|
|
if err == nil && progerr != "" {
|
|
|
|
// If the program had an unhandled error; propagate it to the caller.
|
|
|
|
err = errors.Errorf("an unhandled error occurred: %v", progerr)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Communicate the error, if it exists, or nil if the program exited cleanly.
|
|
|
|
iter.finChan <- run()
|
|
|
|
}()
|
2017-08-30 03:24:12 +02:00
|
|
|
}
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
2018-04-05 18:48:09 +02:00
|
|
|
// resmon implements the pulumirpc.ResourceMonitor interface and acts as the gateway between a language runtime's
|
2017-08-30 03:24:12 +02:00
|
|
|
// evaluation of a program and the internal resource planning and deployment logic.
|
|
|
|
type resmon struct {
|
2017-11-29 20:27:32 +01:00
|
|
|
src *evalSource // the evaluation source.
|
|
|
|
regChan chan *registerResourceEvent // the channel to send resource registrations to.
|
|
|
|
regOutChan chan *registerResourceOutputsEvent // the channel to send resource output registrations to.
|
|
|
|
addr string // the address the host is listening on.
|
|
|
|
cancel chan bool // a channel that can cancel the server.
|
|
|
|
done chan error // a channel that resolves when the server completes.
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// newResourceMonitor creates a new resource monitor RPC server.
|
2017-11-29 20:27:32 +01:00
|
|
|
func newResourceMonitor(src *evalSource, regChan chan *registerResourceEvent,
|
|
|
|
regOutChan chan *registerResourceOutputsEvent) (*resmon, error) {
|
2017-08-30 03:24:12 +02:00
|
|
|
// New up an engine RPC server.
|
|
|
|
resmon := &resmon{
|
2017-11-29 20:27:32 +01:00
|
|
|
src: src,
|
|
|
|
regChan: regChan,
|
|
|
|
regOutChan: regOutChan,
|
|
|
|
cancel: make(chan bool),
|
2017-08-30 03:24:12 +02:00
|
|
|
}
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Fire up a gRPC server and start listening for incomings.
|
|
|
|
port, done, err := rpcutil.Serve(0, resmon.cancel, []func(*grpc.Server) error{
|
|
|
|
func(srv *grpc.Server) error {
|
2018-04-05 18:48:09 +02:00
|
|
|
pulumirpc.RegisterResourceMonitorServer(srv, resmon)
|
2017-08-30 03:24:12 +02:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
2017-06-21 19:31:06 +02:00
|
|
|
|
2017-09-21 19:56:45 +02:00
|
|
|
resmon.addr = fmt.Sprintf("127.0.0.1:%d", port)
|
2017-08-30 03:24:12 +02:00
|
|
|
resmon.done = done
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
return resmon, nil
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Address returns the address at which the monitor's RPC server may be reached.
|
|
|
|
func (rm *resmon) Address() string {
|
2017-09-09 16:37:10 +02:00
|
|
|
return rm.addr
|
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).
2017-06-20 02:24:00 +02:00
|
|
|
}
|
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Cancel signals that the engine should be terminated, awaits its termination, and returns any errors that result.
|
|
|
|
func (rm *resmon) Cancel() error {
|
2018-05-17 00:37:34 +02:00
|
|
|
close(rm.cancel)
|
2017-08-30 03:24:12 +02:00
|
|
|
return <-rm.done
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
2017-09-20 02:23:10 +02:00
|
|
|
// Invoke performs an invocation of a member located in a resource provider.
|
2018-04-05 18:48:09 +02:00
|
|
|
func (rm *resmon) Invoke(ctx context.Context, req *pulumirpc.InvokeRequest) (*pulumirpc.InvokeResponse, error) {
|
2017-09-20 02:23:10 +02:00
|
|
|
// Fetch the token and load up the resource provider.
|
2018-02-06 18:57:32 +01:00
|
|
|
// TODO: we should be flowing version information about this request, but instead, we'll bind to the latest.
|
2017-09-20 02:23:10 +02:00
|
|
|
tok := tokens.ModuleMember(req.GetTok())
|
2018-02-06 18:57:32 +01:00
|
|
|
prov, err := rm.src.plugctx.Host.Provider(tok.Package(), nil)
|
2017-09-20 02:23:10 +02:00
|
|
|
if err != nil {
|
2017-10-14 02:48:54 +02:00
|
|
|
return nil, err
|
|
|
|
} else if prov == nil {
|
|
|
|
return nil, errors.Errorf("could not load resource provider for package '%v' from $PATH", tok.Package())
|
2017-09-20 02:23:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now unpack all of the arguments and prepare to perform the invocation.
|
2017-12-15 16:22:49 +01:00
|
|
|
label := fmt.Sprintf("ResourceMonitor.Invoke(%s)", tok)
|
2017-09-20 02:23:10 +02:00
|
|
|
args, err := plugin.UnmarshalProperties(
|
2017-12-15 16:22:49 +01:00
|
|
|
req.GetArgs(), plugin.MarshalOptions{Label: label, KeepUnknowns: true})
|
2017-09-20 02:23:10 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "failed to unmarshal %v args", tok)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the invoke and then return the arguments.
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof("ResourceMonitor.Invoke received: tok=%v #args=%v", tok, len(args))
|
2017-09-20 02:23:10 +02:00
|
|
|
ret, failures, err := prov.Invoke(tok, args)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "invocation of %v returned an error", tok)
|
|
|
|
}
|
2017-12-15 16:22:49 +01:00
|
|
|
mret, err := plugin.MarshalProperties(ret, plugin.MarshalOptions{Label: label, KeepUnknowns: true})
|
2017-09-20 02:23:10 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "failed to marshal %v return", tok)
|
|
|
|
}
|
2018-04-05 18:48:09 +02:00
|
|
|
var chkfails []*pulumirpc.CheckFailure
|
2017-09-20 02:23:10 +02:00
|
|
|
for _, failure := range failures {
|
2018-04-05 18:48:09 +02:00
|
|
|
chkfails = append(chkfails, &pulumirpc.CheckFailure{
|
2017-09-20 02:23:10 +02:00
|
|
|
Property: string(failure.Property),
|
|
|
|
Reason: failure.Reason,
|
|
|
|
})
|
|
|
|
}
|
2018-04-05 18:48:09 +02:00
|
|
|
return &pulumirpc.InvokeResponse{Return: mret, Failures: chkfails}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadResource reads the current state associated with a resource from its provider plugin.
|
|
|
|
func (rm *resmon) ReadResource(ctx context.Context,
|
|
|
|
req *pulumirpc.ReadResourceRequest) (*pulumirpc.ReadResourceResponse, error) {
|
|
|
|
// Read the basic inputs necessary to identify the plugin.
|
|
|
|
t := tokens.Type(req.GetType())
|
|
|
|
name := tokens.QName(req.GetName())
|
|
|
|
parent := resource.URN(req.GetParent())
|
|
|
|
prov, err := rm.src.plugctx.Host.Provider(t.Package(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if prov == nil {
|
|
|
|
return nil, errors.Errorf("could not load resource provider for package '%v' from $PATH", t.Package())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Manufacture a URN that is based on the program evaluation context.
|
|
|
|
var pt tokens.Type
|
|
|
|
if parent != "" {
|
|
|
|
pt = parent.Type()
|
|
|
|
}
|
|
|
|
urn := resource.NewURN(rm.src.Stack(), rm.src.Project(), pt, t, name)
|
|
|
|
|
2018-04-07 16:52:10 +02:00
|
|
|
// Now get the ID. If it is an unknown value -- as might happen during planning when, for example, reading
|
|
|
|
// the output of another resource's output property -- then we can skip the RPC as it can't possibly do anything.
|
|
|
|
id := resource.ID(req.GetId())
|
2018-04-05 18:48:09 +02:00
|
|
|
label := fmt.Sprintf("ResourceMonitor.ReadResource(%s, %s, %s)", id, t, name)
|
2018-04-07 16:52:10 +02:00
|
|
|
resp := &pulumirpc.ReadResourceResponse{Urn: string(urn)}
|
2018-04-05 18:48:09 +02:00
|
|
|
|
2018-04-07 16:52:10 +02:00
|
|
|
if id != plugin.UnknownStringValue {
|
|
|
|
// Unmarshal any additional state that came with the message.
|
|
|
|
props, err := plugin.UnmarshalProperties(
|
|
|
|
req.GetProperties(), plugin.MarshalOptions{Label: label, KeepUnknowns: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "failed to unmarshal read properties for resource %s", id)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now actually call the plugin to read the state and then return the results.
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof("ResourceMonitor.ReadResource received: %s #props=%d", label, len(props))
|
2018-04-07 16:52:10 +02:00
|
|
|
result, err := prov.Read(urn, id, props)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "reading resource %s state", urn)
|
|
|
|
}
|
|
|
|
marshaled, err := plugin.MarshalProperties(result, plugin.MarshalOptions{Label: label, KeepUnknowns: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "failed to marshal %s return state", urn)
|
|
|
|
}
|
|
|
|
resp.Properties = marshaled
|
2018-04-05 18:48:09 +02:00
|
|
|
}
|
2018-04-07 16:52:10 +02:00
|
|
|
|
|
|
|
return resp, nil
|
2017-09-20 02:23:10 +02:00
|
|
|
}
|
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
// RegisterResource is invoked by a language process when a new resource has been allocated.
|
|
|
|
func (rm *resmon) RegisterResource(ctx context.Context,
|
2018-04-05 18:48:09 +02:00
|
|
|
req *pulumirpc.RegisterResourceRequest) (*pulumirpc.RegisterResourceResponse, error) {
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Communicate the type, name, and object information to the iterator that is awaiting us.
|
2017-12-15 16:22:49 +01:00
|
|
|
t := tokens.Type(req.GetType())
|
|
|
|
name := tokens.QName(req.GetName())
|
|
|
|
label := fmt.Sprintf("ResourceMonitor.RegisterResource(%s,%s)", t, name)
|
|
|
|
custom := req.GetCustom()
|
|
|
|
parent := resource.URN(req.GetParent())
|
Implement resource protection (#751)
This change implements resource protection, as per pulumi/pulumi#689.
The overall idea is that a resource can be marked as "protect: true",
which will prevent deletion of that resource for any reason whatsoever
(straight deletion, replacement, etc). This is expressed in the
program. To "unprotect" a resource, one must perform an update setting
"protect: false", and then afterwards, they can delete the resource.
For example:
let res = new MyResource("precious", { .. }, { protect: true });
Afterwards, the resource will display in the CLI with a lock icon, and
any attempts to remove it will fail in the usual ways (in planning or,
worst case, during an actual update).
This was done by adding a new ResourceOptions bag parameter to the
base Resource types. This is unfortunately a breaking change, but now
is the right time to take this one. We had been adding new settings
one by one -- like parent and dependsOn -- and this new approach will
set us up to add any number of additional settings down the road,
without needing to worry about breaking anything ever again.
This is related to protected stacks, as described in
pulumi/pulumi-service#399. Most likely this will serve as a foundational
building block that enables the coarser grained policy management.
2017-12-20 23:31:07 +01:00
|
|
|
protect := req.GetProtect()
|
2018-02-22 00:11:21 +01:00
|
|
|
|
2018-02-22 21:52:50 +01:00
|
|
|
dependencies := []resource.URN{}
|
2018-02-22 00:11:21 +01:00
|
|
|
for _, dependingURN := range req.GetDependencies() {
|
|
|
|
dependencies = append(dependencies, resource.URN(dependingURN))
|
|
|
|
}
|
|
|
|
|
2017-09-15 01:40:44 +02:00
|
|
|
props, err := plugin.UnmarshalProperties(
|
2017-12-15 16:22:49 +01:00
|
|
|
req.GetObject(), plugin.MarshalOptions{Label: label, KeepUnknowns: true, ComputeAssetHashes: true})
|
2017-09-15 01:40:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
Implement components
This change implements core support for "components" in the Pulumi
Fabric. This work is described further in pulumi/pulumi#340, where
we are still discussing some of the finer points.
In a nutshell, resources no longer imply external providers. It's
entirely possible to have a resource that logically represents
something but without having a physical manifestation that needs to
be tracked and managed by our typical CRUD operations.
For example, the aws/serverless/Function helper is one such type.
It aggregates Lambda-related resources and exposes a nice interface.
All of the Pulumi Cloud Framework resources are also examples.
To indicate that a resource does participate in the usual CRUD resource
provider, it simply derives from ExternalResource instead of Resource.
All resources now have the ability to adopt children. This is purely
a metadata/tagging thing, and will help us roll up displays, provide
attribution to the developer, and even hide aspects of the resource
graph as appropriate (e.g., when they are implementation details).
Our use of this capability is ultra limited right now; in fact, the
only place we display children is in the CLI output. For instance:
+ aws:serverless:Function: (create)
[urn=urn:pulumi:demo::serverless::aws:serverless:Function::mylambda]
=> urn:pulumi:demo::serverless::aws:iam/role:Role::mylambda-iamrole
=> urn:pulumi:demo::serverless::aws:iam/rolePolicyAttachment:RolePolicyAttachment::mylambda-iampolicy-0
=> urn:pulumi:demo::serverless::aws:lambda/function:Function::mylambda
The bit indicating whether a resource is external or not is tracked
in the resulting checkpoint file, along with any of its children.
2017-10-14 23:18:43 +02:00
|
|
|
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof(
|
2018-02-22 00:11:21 +01:00
|
|
|
"ResourceMonitor.RegisterResource received: t=%v, name=%v, custom=%v, #props=%v, parent=%v, protect=%v, deps=%v",
|
|
|
|
t, name, custom, len(props), parent, protect, dependencies)
|
2017-11-21 02:38:09 +01:00
|
|
|
|
|
|
|
// Send the goal state to the engine.
|
2017-11-29 20:27:32 +01:00
|
|
|
step := ®isterResourceEvent{
|
2018-02-22 00:11:21 +01:00
|
|
|
goal: resource.NewGoal(t, name, custom, props, parent, protect, dependencies),
|
2017-11-29 20:27:32 +01:00
|
|
|
done: make(chan *RegisterResult),
|
2017-06-15 00:52:36 +02:00
|
|
|
}
|
2018-05-17 00:37:34 +02:00
|
|
|
|
|
|
|
select {
|
|
|
|
case rm.regChan <- step:
|
|
|
|
case <-rm.cancel:
|
|
|
|
logging.V(5).Infof("ResourceMonitor.RegisterResource operation canceled, name=%s", name)
|
|
|
|
return nil, rpcerror.New(codes.Unavailable, "resource monitor shut down while sending resource registration")
|
|
|
|
}
|
2017-11-21 02:38:09 +01:00
|
|
|
|
|
|
|
// Now block waiting for the operation to finish.
|
2018-05-17 00:37:34 +02:00
|
|
|
var result *RegisterResult
|
|
|
|
select {
|
|
|
|
case result = <-step.done:
|
|
|
|
case <-rm.cancel:
|
|
|
|
logging.V(5).Infof("ResourceMonitor.RegisterResource operation canceled, name=%s", name)
|
|
|
|
return nil, rpcerror.New(codes.Unavailable, "resource monitor shut down while waiting on step's done channel")
|
|
|
|
}
|
|
|
|
|
2017-11-21 02:38:09 +01:00
|
|
|
state := result.State
|
2017-12-03 01:34:16 +01:00
|
|
|
props = state.All()
|
2017-11-21 02:38:09 +01:00
|
|
|
stable := result.Stable
|
Add a notion of stable properties
This change adds the capability for a resource provider to indicate
that, where an action carried out in response to a diff, a certain set
of properties would be "stable"; that is to say, they are guaranteed
not to change. As a result, properties may be resolved to their final
values during previewing, avoiding erroneous cascading impacts.
This avoids the ever-annoying situation I keep running into when demoing:
when adding or removing an ingress rule to a security group, we ripple
the impact through the instance, and claim it must be replaced, because
that instance depends on the security group via its name. Well, the name
is a great example of a stable property, in that it will never change, and
so this is truly unfortunate and always adds uncertainty into the demos.
Particularly since the actual update doesn't need to perform replacements.
This resolves pulumi/pulumi#330.
2017-10-04 14:22:21 +02:00
|
|
|
var stables []string
|
2017-11-21 02:38:09 +01:00
|
|
|
for _, sta := range result.Stables {
|
Add a notion of stable properties
This change adds the capability for a resource provider to indicate
that, where an action carried out in response to a diff, a certain set
of properties would be "stable"; that is to say, they are guaranteed
not to change. As a result, properties may be resolved to their final
values during previewing, avoiding erroneous cascading impacts.
This avoids the ever-annoying situation I keep running into when demoing:
when adding or removing an ingress rule to a security group, we ripple
the impact through the instance, and claim it must be replaced, because
that instance depends on the security group via its name. Well, the name
is a great example of a stable property, in that it will never change, and
so this is truly unfortunate and always adds uncertainty into the demos.
Particularly since the actual update doesn't need to perform replacements.
This resolves pulumi/pulumi#330.
2017-10-04 14:22:21 +02:00
|
|
|
stables = append(stables, string(sta))
|
|
|
|
}
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof(
|
2017-12-10 17:37:22 +01:00
|
|
|
"ResourceMonitor.RegisterResource operation finished: t=%v, urn=%v, stable=%v, #stables=%v #outs=%v",
|
2017-12-03 01:34:16 +01:00
|
|
|
state.Type, state.URN, stable, len(stables), len(props))
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
2017-08-30 03:24:12 +02:00
|
|
|
// Finally, unpack the response into properties that we can return to the language runtime. This mostly includes
|
|
|
|
// an ID, URN, and defaults and output properties that will all be blitted back onto the runtime object.
|
2017-12-15 16:22:49 +01:00
|
|
|
obj, err := plugin.MarshalProperties(props, plugin.MarshalOptions{Label: label, KeepUnknowns: true})
|
2017-09-15 01:40:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-04-05 18:48:09 +02:00
|
|
|
return &pulumirpc.RegisterResourceResponse{
|
2017-11-29 20:27:32 +01:00
|
|
|
Urn: string(state.URN),
|
Add a notion of stable properties
This change adds the capability for a resource provider to indicate
that, where an action carried out in response to a diff, a certain set
of properties would be "stable"; that is to say, they are guaranteed
not to change. As a result, properties may be resolved to their final
values during previewing, avoiding erroneous cascading impacts.
This avoids the ever-annoying situation I keep running into when demoing:
when adding or removing an ingress rule to a security group, we ripple
the impact through the instance, and claim it must be replaced, because
that instance depends on the security group via its name. Well, the name
is a great example of a stable property, in that it will never change, and
so this is truly unfortunate and always adds uncertainty into the demos.
Particularly since the actual update doesn't need to perform replacements.
This resolves pulumi/pulumi#330.
2017-10-04 14:22:21 +02:00
|
|
|
Id: string(state.ID),
|
2017-11-29 20:27:32 +01:00
|
|
|
Object: obj,
|
Add a notion of stable properties
This change adds the capability for a resource provider to indicate
that, where an action carried out in response to a diff, a certain set
of properties would be "stable"; that is to say, they are guaranteed
not to change. As a result, properties may be resolved to their final
values during previewing, avoiding erroneous cascading impacts.
This avoids the ever-annoying situation I keep running into when demoing:
when adding or removing an ingress rule to a security group, we ripple
the impact through the instance, and claim it must be replaced, because
that instance depends on the security group via its name. Well, the name
is a great example of a stable property, in that it will never change, and
so this is truly unfortunate and always adds uncertainty into the demos.
Particularly since the actual update doesn't need to perform replacements.
This resolves pulumi/pulumi#330.
2017-10-04 14:22:21 +02:00
|
|
|
Stable: stable,
|
|
|
|
Stables: stables,
|
2017-08-30 03:24:12 +02:00
|
|
|
}, nil
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
// RegisterResourceOutputs records some new output properties for a resource that have arrived after its initial
|
|
|
|
// provisioning. These will make their way into the eventual checkpoint state file for that resource.
|
|
|
|
func (rm *resmon) RegisterResourceOutputs(ctx context.Context,
|
2018-04-05 18:48:09 +02:00
|
|
|
req *pulumirpc.RegisterResourceOutputsRequest) (*pbempty.Empty, error) {
|
2017-11-29 20:27:32 +01:00
|
|
|
|
|
|
|
// Obtain and validate the message's inputs (a URN plus the output property map).
|
|
|
|
urn := resource.URN(req.GetUrn())
|
|
|
|
if urn == "" {
|
|
|
|
return nil, errors.New("missing required URN")
|
|
|
|
}
|
2017-12-15 16:22:49 +01:00
|
|
|
label := fmt.Sprintf("ResourceMonitor.RegisterResourceOutputs(%s)", urn)
|
2017-11-29 20:27:32 +01:00
|
|
|
outs, err := plugin.UnmarshalProperties(
|
2017-12-15 16:22:49 +01:00
|
|
|
req.GetOutputs(), plugin.MarshalOptions{Label: label, KeepUnknowns: true, ComputeAssetHashes: true})
|
2017-11-29 20:27:32 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "cannot unmarshal output properties")
|
|
|
|
}
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof("ResourceMonitor.RegisterResourceOutputs received: urn=%v, #outs=%v", urn, len(outs))
|
2017-11-29 20:27:32 +01:00
|
|
|
|
|
|
|
// Now send the step over to the engine to perform.
|
|
|
|
step := ®isterResourceOutputsEvent{
|
|
|
|
urn: urn,
|
|
|
|
outputs: outs,
|
|
|
|
done: make(chan bool),
|
|
|
|
}
|
2018-05-17 00:37:34 +02:00
|
|
|
|
|
|
|
select {
|
|
|
|
case rm.regOutChan <- step:
|
|
|
|
case <-rm.cancel:
|
|
|
|
logging.V(5).Infof("ResourceMonitor.RegisterResourceOutputs operation canceled, urn=%s", urn)
|
|
|
|
return nil, rpcerror.New(codes.Unavailable, "resource monitor shut down while sending resource outputs")
|
|
|
|
}
|
2017-11-29 20:27:32 +01:00
|
|
|
|
|
|
|
// Now block waiting for the operation to finish.
|
2018-05-17 00:37:34 +02:00
|
|
|
select {
|
|
|
|
case <-step.done:
|
|
|
|
case <-rm.cancel:
|
|
|
|
logging.V(5).Infof("ResourceMonitor.RegisterResourceOutputs operation canceled, urn=%s", urn)
|
|
|
|
return nil, rpcerror.New(codes.Unavailable, "resource monitor shut down while waiting on output step's done channel")
|
|
|
|
}
|
|
|
|
|
2018-05-16 00:28:00 +02:00
|
|
|
logging.V(5).Infof(
|
2017-11-29 20:27:32 +01:00
|
|
|
"ResourceMonitor.RegisterResourceOutputs operation finished: urn=%v, #outs=%v", urn, len(outs))
|
|
|
|
return &pbempty.Empty{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type registerResourceEvent struct {
|
|
|
|
goal *resource.Goal // the resource goal state produced by the iterator.
|
|
|
|
done chan *RegisterResult // the channel to communicate with after the resource state is available.
|
2017-09-05 19:01:00 +02:00
|
|
|
}
|
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
var _ RegisterResourceEvent = (*registerResourceEvent)(nil)
|
2017-11-21 02:38:09 +01:00
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
func (g *registerResourceEvent) event() {}
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
func (g *registerResourceEvent) Goal() *resource.Goal {
|
2017-08-30 03:24:12 +02:00
|
|
|
return g.goal
|
|
|
|
}
|
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).
2017-06-20 02:24:00 +02:00
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
func (g *registerResourceEvent) Done(result *RegisterResult) {
|
2017-08-30 03:24:12 +02:00
|
|
|
// Communicate the resulting state back to the RPC thread, which is parked awaiting our reply.
|
2017-11-29 20:27:32 +01:00
|
|
|
g.done <- result
|
2017-11-21 02:38:09 +01:00
|
|
|
}
|
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
type registerResourceOutputsEvent struct {
|
|
|
|
urn resource.URN // the URN to which this completion applies.
|
|
|
|
outputs resource.PropertyMap // an optional property bag for output properties.
|
|
|
|
done chan bool // the channel to communicate with after the operation completes.
|
2017-11-21 02:38:09 +01:00
|
|
|
}
|
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
var _ RegisterResourceOutputsEvent = (*registerResourceOutputsEvent)(nil)
|
2017-11-21 02:38:09 +01:00
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
func (g *registerResourceOutputsEvent) event() {}
|
2017-11-21 02:38:09 +01:00
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
func (g *registerResourceOutputsEvent) URN() resource.URN {
|
2017-11-21 02:38:09 +01:00
|
|
|
return g.urn
|
|
|
|
}
|
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
func (g *registerResourceOutputsEvent) Outputs() resource.PropertyMap {
|
|
|
|
return g.outputs
|
2017-11-21 02:38:09 +01:00
|
|
|
}
|
|
|
|
|
2017-11-29 20:27:32 +01:00
|
|
|
func (g *registerResourceOutputsEvent) Done() {
|
2017-11-21 02:38:09 +01:00
|
|
|
// Communicate the resulting state back to the RPC thread, which is parked awaiting our reply.
|
2017-11-29 20:27:32 +01:00
|
|
|
g.done <- true
|
Make more progress on the new deployment model
This change restructures a lot more pertaining to deployments, snapshots,
environments, and the like.
The most notable change is that the notion of a deploy.Source is introduced,
which splits the responsibility between the deploy.Plan -- which simply
understands how to compute and carry out deployment plans -- and the idea
of something that can produce new objects on-demand during deployment.
The primary such implementation is evalSource, which encapsulates an
interpreter and takes a package, args, and config map, and proceeds to run
the interpreter in a distinct goroutine. It synchronizes as needed to
poke and prod the interpreter along its path to create new resource objects.
There are two other sources, however. First, a nullSource, which simply
refuses to create new objects. This can be handy when writing isolated
tests but is also used to simulate the "empty" environment as necessary to
do a complete teardown of the target environment. Second, a fixedSource,
which takes a pre-computed array of objects, and hands those, in order, to
the planning engine; this is mostly useful as a testing technique.
Boatloads of code is now changed and updated in the various CLI commands.
This further chugs along towards pulumi/lumi#90. The end is in sight.
2017-06-10 20:50:47 +02:00
|
|
|
}
|