2017-06-10 03:34:37 +02:00
|
|
|
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
|
|
|
// contributor license agreements. See the NOTICE file distributed with
|
|
|
|
// this work for additional information regarding copyright ownership.
|
|
|
|
// Pulumi licenses this file to You 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
|
2017-06-10 03:34:37 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/golang/glog"
|
|
|
|
goerr "github.com/pkg/errors"
|
|
|
|
|
|
|
|
"github.com/pulumi/lumi/pkg/compiler/errors"
|
|
|
|
"github.com/pulumi/lumi/pkg/resource"
|
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
|
|
|
"github.com/pulumi/lumi/pkg/resource/plugin"
|
2017-06-10 03:34:37 +02:00
|
|
|
"github.com/pulumi/lumi/pkg/tokens"
|
|
|
|
"github.com/pulumi/lumi/pkg/util/contract"
|
|
|
|
)
|
|
|
|
|
|
|
|
// TODO[pulumi/lumi#106]: parallelism.
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// that failed, if the error is non-nil; and finally the state of the resource modified in the failing step.
|
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 (p *Plan) Apply(prog Progress) (PlanSummary, *Step, resource.Status, error) {
|
2017-06-10 03:34:37 +02:00
|
|
|
// Fetch a plan iterator and keep walking it until we are done.
|
|
|
|
iter, err := p.Iterate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, resource.StatusOK, err
|
|
|
|
}
|
|
|
|
n := 1
|
|
|
|
step, err := iter.Next()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, resource.StatusOK, err
|
|
|
|
}
|
|
|
|
for step != nil {
|
|
|
|
// Perform pre-application progress reporting.
|
|
|
|
if prog != nil {
|
|
|
|
prog.Before(step)
|
|
|
|
}
|
|
|
|
|
|
|
|
rst, err := step.Apply()
|
|
|
|
|
|
|
|
// Perform post-application progress reporting.
|
|
|
|
if prog != nil {
|
|
|
|
prog.After(step, rst, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If an error occurred, exit early.
|
|
|
|
if err != nil {
|
|
|
|
glog.V(7).Infof("Plan step #%v failed [%v]: %v", n, step.Op(), 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
|
|
|
return iter, step, rst, err
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
glog.V(7).Infof("Plan step #%v succeeded [%v]", n, step.Op())
|
|
|
|
step, err = iter.Next()
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
|
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
|
|
|
// Finally, return a summary and the resulting plan information.
|
|
|
|
return iter, nil, resource.StatusOK, nil
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate initializes and returns an iterator that can be used to step through a plan's individual steps.
|
|
|
|
func (p *Plan) Iterate() (*PlanIterator, 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
|
|
|
// Ask the source for its iterator.
|
|
|
|
src, err := p.new.Iterate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an iterator that can be used to perform the planning process.
|
|
|
|
return &PlanIterator{
|
2017-06-11 17:09:20 +02:00
|
|
|
p: p,
|
|
|
|
src: src,
|
|
|
|
creates: make(map[resource.URN]bool),
|
|
|
|
updates: make(map[resource.URN]bool),
|
|
|
|
replaces: make(map[resource.URN]bool),
|
|
|
|
deletes: make(map[resource.URN]bool),
|
|
|
|
sames: make(map[resource.URN]bool),
|
2017-06-12 16:16:08 +02:00
|
|
|
dones: make(map[*resource.State]bool),
|
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
|
|
|
}, nil
|
|
|
|
}
|
2017-06-10 03:34:37 +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
|
|
|
// PlanSummary is an interface for summarizing the progress of a plan.
|
|
|
|
type PlanSummary interface {
|
|
|
|
Steps() int
|
|
|
|
Creates() map[resource.URN]bool
|
|
|
|
Updates() map[resource.URN]bool
|
|
|
|
Replaces() map[resource.URN]bool
|
|
|
|
Deletes() map[resource.URN]bool
|
|
|
|
Sames() map[resource.URN]bool
|
|
|
|
Resources() []*resource.State
|
|
|
|
Snap() *Snapshot
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// PlanIterator can be used to step through and/or execute a plan's proposed actions.
|
|
|
|
type PlanIterator struct {
|
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
|
|
|
p *Plan // the plan to which this iterator belongs.
|
|
|
|
src SourceIterator // the iterator that fetches source resources.
|
2017-06-10 03:34:37 +02:00
|
|
|
|
|
|
|
creates map[resource.URN]bool // URNs discovered to be created.
|
|
|
|
updates map[resource.URN]bool // URNs discovered to be updated.
|
|
|
|
replaces map[resource.URN]bool // URNs discovered to be replaced.
|
|
|
|
deletes map[resource.URN]bool // URNs discovered to be deleted.
|
|
|
|
sames map[resource.URN]bool // URNs discovered to be the same.
|
|
|
|
|
2017-06-12 16:16:08 +02:00
|
|
|
delqueue []*resource.State // a queue of deletes left to perform.
|
|
|
|
resources []*resource.State // the resulting ordered resource states.
|
|
|
|
dones map[*resource.State]bool // true for each old state we're done with.
|
2017-06-10 03:34:37 +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
|
|
|
srcdone bool // true if the source interpreter has been run to completion.
|
|
|
|
done bool // true if the planning and associated iteration has finished.
|
2017-06-10 03:34:37 +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
|
|
|
func (iter *PlanIterator) Plan() *Plan { return iter.p }
|
|
|
|
func (iter *PlanIterator) Steps() int {
|
|
|
|
return len(iter.creates) + len(iter.updates) + len(iter.replaces) + len(iter.deletes)
|
2017-06-10 03:34:37 +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
|
|
|
func (iter *PlanIterator) Creates() map[resource.URN]bool { return iter.creates }
|
|
|
|
func (iter *PlanIterator) Updates() map[resource.URN]bool { return iter.updates }
|
|
|
|
func (iter *PlanIterator) Replaces() map[resource.URN]bool { return iter.replaces }
|
|
|
|
func (iter *PlanIterator) Deletes() map[resource.URN]bool { return iter.deletes }
|
|
|
|
func (iter *PlanIterator) Sames() map[resource.URN]bool { return iter.sames }
|
|
|
|
func (iter *PlanIterator) Resources() []*resource.State { return iter.resources }
|
2017-06-12 16:16:08 +02:00
|
|
|
func (iter *PlanIterator) Dones() map[*resource.State]bool { return iter.dones }
|
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 *PlanIterator) Done() bool { return iter.done }
|
2017-06-10 03:34:37 +02:00
|
|
|
|
|
|
|
// 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
|
|
|
|
// taken, Next will return a nil step pointer.
|
|
|
|
func (iter *PlanIterator) Next() (*Step, error) {
|
|
|
|
for !iter.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
|
|
|
if !iter.srcdone {
|
|
|
|
obj, ctx, err := iter.src.Next()
|
2017-06-10 03:34:37 +02:00
|
|
|
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
|
|
|
} else if obj == nil {
|
|
|
|
// If the source is done, note it, and don't go back for more.
|
|
|
|
iter.srcdone = true
|
2017-06-10 03:34:37 +02:00
|
|
|
iter.delqueue = iter.calculateDeletes()
|
|
|
|
} else {
|
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
|
|
|
step, err := iter.nextResource(obj, ctx)
|
2017-06-10 03:34:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if step != nil {
|
|
|
|
return step, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the step returned was nil, this resource is fine, so we'll keep on going.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// The interpreter has finished, so we need to now drain any deletions that piled up.
|
|
|
|
if step := iter.nextDelete(); step != nil {
|
|
|
|
return step, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, if the deletes have quiesced, there is nothing remaining in this plan; leave.
|
|
|
|
iter.done = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// nextResource produces a new step for a given resource or nil if there isn't one to perform.
|
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 *PlanIterator) nextResource(new *resource.Object, ctx tokens.Module) (*Step, error) {
|
2017-06-10 03:34:37 +02:00
|
|
|
// Take a moment in time snapshot of the live object's properties.
|
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
|
|
|
t := new.Type()
|
2017-06-11 17:09:20 +02:00
|
|
|
inputs := new.CopyProperties()
|
2017-06-10 03:34:37 +02:00
|
|
|
|
|
|
|
// Fetch the provider for this resource type.
|
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
|
|
|
prov, err := iter.Provider(new)
|
2017-06-10 03:34:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the resource's name from its provider, and use it to construct a URN.
|
2017-06-11 17:09:20 +02:00
|
|
|
name, err := prov.Name(t, inputs)
|
2017-06-10 03:34:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-06-11 02:03:58 +02:00
|
|
|
urn := resource.NewURN(iter.p.Target().Name, ctx, t, name)
|
2017-06-10 03:34:37 +02:00
|
|
|
|
|
|
|
// First ensure the provider is okay with this resource.
|
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
|
|
|
var invalid bool
|
2017-06-11 17:09:20 +02:00
|
|
|
failures, err := prov.Check(new.Type(), inputs)
|
2017-06-10 03:34:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, failure := range failures {
|
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
|
|
|
invalid = true
|
2017-06-16 19:04:49 +02:00
|
|
|
var v resource.PropertyValue
|
|
|
|
if failure.Property != "" {
|
|
|
|
v = inputs[failure.Property]
|
|
|
|
}
|
Simplify Check; make it tolerant of computed values
This change simplifies the generated Check interface for providers.
Instead of
Check(ctx context.Context, obj *T) ([]error, error)
where T is the resource type, we have
Check(ctx context.Context, obj *T, property string) error
This is done so that we can drive the calls to Check one property
at a time, allowing us to skip any that are computed. (Otherwise,
we may fail the verification erroneously.)
This has the added advantage that the Check implementations are
simpler and can simply return a single error. Furthermore, the
generated RPC code handles wrapping the result, so we can just do
return errors.New("bad");
rather than the previous reflection-laden junk
return resource.NewFieldError(
reflect.TypeOf(obj), awsservice.AWSResource_Property,
errors.New("bad"))
2017-06-16 22:34:11 +02:00
|
|
|
iter.p.Diag().Errorf(errors.ErrorResourcePropertyInvalidValue, urn.Name(), failure.Property, v, failure.Reason)
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Next, give each analyzer -- if any -- a chance to inspect the resource too.
|
|
|
|
for _, a := range iter.p.analyzers {
|
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
|
|
|
analyzer, err := iter.p.ctx.Host.Analyzer(a)
|
2017-06-10 03:34:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-06-11 17:09:20 +02:00
|
|
|
failures, err := analyzer.Analyze(t, inputs)
|
2017-06-10 03:34:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, failure := range failures {
|
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
|
|
|
invalid = true
|
2017-06-15 02:00:13 +02:00
|
|
|
iter.p.Diag().Errorf(errors.ErrorAnalyzeResourceFailure, a, urn, failure.Property, failure.Reason)
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the resource isn't valid, don't proceed any further.
|
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
|
|
|
if invalid {
|
2017-06-10 03:34:37 +02:00
|
|
|
return nil, goerr.New("One or more resource validation errors occurred; refusing to proceed")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now decide what to do, step-wise:
|
|
|
|
//
|
|
|
|
// * If the URN exists in the old snapshot, and it has been updated,
|
|
|
|
// - Check whether the update requires replacement.
|
|
|
|
// - If yes, create a new copy, and mark it as having been replaced.
|
|
|
|
// - If no, simply update the existing resource in place.
|
|
|
|
//
|
|
|
|
// * If the URN does not exist in the old snapshot, create the resource anew.
|
|
|
|
//
|
2017-06-11 17:09:20 +02:00
|
|
|
if old, hasold := iter.p.Olds()[urn]; hasold {
|
|
|
|
contract.Assert(old != nil && old.Type() == new.Type())
|
|
|
|
|
2017-06-10 03:34:37 +02:00
|
|
|
// The resource exists in both new and old; it could be an update. This constitutes an update if the old
|
|
|
|
// and new properties don't match exactly. It is also possible we'll need to replace the resource if the
|
|
|
|
// update impact assessment says so. In this case, the resource's ID will change, which might have a
|
|
|
|
// cascading impact on subsequent updates too, since those IDs must trigger recreations, etc.
|
|
|
|
oldprops := old.Inputs()
|
2017-06-11 17:09:20 +02:00
|
|
|
if oldprops.DeepEquals(inputs) {
|
|
|
|
// No need to update anything, the properties didn't change.
|
2017-06-10 03:34:37 +02:00
|
|
|
iter.sames[urn] = true
|
|
|
|
glog.V(7).Infof("Planner decided not to update '%v'", urn)
|
2017-06-11 17:09:20 +02:00
|
|
|
return NewSameStep(iter, old, new, inputs), nil
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// The properties changed; we need to figure out whether to do an update or replacement.
|
2017-06-11 17:09:20 +02:00
|
|
|
replacements, _, err := prov.InspectChange(t, old.ID(), oldprops, inputs)
|
2017-06-10 03:34:37 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if len(replacements) > 0 {
|
|
|
|
iter.replaces[urn] = true
|
2017-06-15 02:00:13 +02:00
|
|
|
glog.V(7).Infof("Planner decided to replace '%v' (oldprops=%v inputs=%v)", urn, oldprops, inputs)
|
2017-06-11 17:09:20 +02:00
|
|
|
return NewReplaceCreateStep(iter, old, new, inputs, replacements), nil
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
iter.updates[urn] = true
|
2017-06-15 02:00:13 +02:00
|
|
|
glog.V(7).Infof("Planner decided to update '%v' (oldprops=%v inputs=%v", urn, oldprops, inputs)
|
2017-06-11 17:09:20 +02:00
|
|
|
return NewUpdateStep(iter, old, new, inputs), nil
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, the resource isn't in the old map, so it must be a resource creation.
|
|
|
|
iter.creates[urn] = true
|
|
|
|
glog.V(7).Infof("Planner decided to create '%v'", urn)
|
2017-06-15 02:00:13 +02:00
|
|
|
return NewCreateStep(iter, urn, new, inputs), nil
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// nextDelete produces a new step that deletes a resource if necessary.
|
|
|
|
func (iter *PlanIterator) nextDelete() *Step {
|
|
|
|
if len(iter.delqueue) > 0 {
|
|
|
|
del := iter.delqueue[0]
|
|
|
|
iter.delqueue = iter.delqueue[1:]
|
|
|
|
urn := del.URN()
|
|
|
|
iter.deletes[urn] = true
|
2017-06-11 02:03:58 +02:00
|
|
|
if iter.replaces[urn] {
|
|
|
|
glog.V(7).Infof("Planner decided to delete '%v' due to replacement", urn)
|
|
|
|
return NewReplaceDeleteStep(iter, del)
|
|
|
|
}
|
2017-06-10 03:34:37 +02:00
|
|
|
glog.V(7).Infof("Planner decided to delete '%v'", urn)
|
|
|
|
return NewDeleteStep(iter, del)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculateDeletes creates a list of deletes to perform. This will include any resources in the snapshot that were
|
|
|
|
// not encountered in the input, along with any resources that were replaced.
|
|
|
|
func (iter *PlanIterator) calculateDeletes() []*resource.State {
|
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
|
|
|
// To compute the deletion list, we must walk the list of old resources *backwards*. This is because the list is
|
|
|
|
// stored in dependency order, and earlier elements are possibly leaf nodes for later elements. We must not delete
|
|
|
|
// dependencies prior to their dependent nodes.
|
2017-06-10 03:34:37 +02:00
|
|
|
var dels []*resource.State
|
2017-06-11 15:52:56 +02:00
|
|
|
if prev := iter.p.prev; prev != nil {
|
|
|
|
for i := len(prev.Resources) - 1; i >= 0; i-- {
|
|
|
|
res := prev.Resources[i]
|
|
|
|
urn := res.URN()
|
|
|
|
contract.Assert(!iter.creates[urn])
|
2017-06-11 17:09:20 +02:00
|
|
|
if (!iter.sames[urn] && !iter.updates[urn]) || iter.replaces[urn] {
|
2017-06-11 15:52:56 +02:00
|
|
|
dels = append(dels, res)
|
|
|
|
}
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return dels
|
|
|
|
}
|
|
|
|
|
|
|
|
// Snap returns a fresh snapshot that takes into account everything that has happend up till this point. Namely, if a
|
|
|
|
// failure happens partway through, the untouched snapshot elements will be retained, while any updates will be
|
|
|
|
// preserved. If no failure happens, the snapshot naturally reflects the final state of all resources.
|
|
|
|
func (iter *PlanIterator) Snap() *Snapshot {
|
2017-06-12 16:16:08 +02:00
|
|
|
var resources []*resource.State
|
|
|
|
|
|
|
|
// If we didn't finish the execution, we must produce a partial snapshot of old plus new states.
|
|
|
|
if !iter.done {
|
|
|
|
if prev := iter.p.prev; prev != nil {
|
|
|
|
for _, res := range prev.Resources {
|
|
|
|
if !iter.dones[res] {
|
|
|
|
resources = append(resources, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always add the new resoures afterwards that got produced during the evaluation of the current plan.
|
|
|
|
resources = append(resources, iter.resources...)
|
|
|
|
|
|
|
|
return NewSnapshot(iter.p.Target().Name, resources, iter.p.new.Info())
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarkStateSnapshot marks an old state snapshot as being processed. This is done to recover from failures partway
|
|
|
|
// through the application of a deployment plan. Any old state that has not yet been recovered needs to be kept.
|
|
|
|
func (iter *PlanIterator) MarkStateSnapshot(state *resource.State) {
|
|
|
|
iter.dones[state] = true
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// AppendStateSnapshot appends a resource's state to the current snapshot.
|
|
|
|
func (iter *PlanIterator) AppendStateSnapshot(state *resource.State) {
|
2017-06-12 16:16:08 +02:00
|
|
|
iter.resources = append(iter.resources, state)
|
2017-06-10 03:34:37 +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
|
|
|
// 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.
|
|
|
|
func (iter *PlanIterator) Provider(res resource.Resource) (plugin.Provider, error) {
|
|
|
|
t := res.Type()
|
|
|
|
pkg := t.Package()
|
|
|
|
return iter.p.ctx.Host.Provider(pkg)
|
2017-06-10 03:34:37 +02:00
|
|
|
}
|