-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wip: stub structs and logic for a bundle workflow
* resolve a dependency graph * identify the order of execution * create new call path to execute bundles from a workflow (i.e. jobs) * Add secret strategy for resolving data from the workflow * Support workflow wiring Signed-off-by: Carolyn Van Slyck <me@carolynvanslyck.com> wip: porter strategy Signed-off-by: Carolyn Van Slyck <me@carolynvanslyck.com>
- Loading branch information
Showing
53 changed files
with
2,306 additions
and
199 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package v2 | ||
|
||
import ( | ||
"sort" | ||
|
||
"get.porter.sh/porter/pkg/cnab" | ||
depsv2ext "get.porter.sh/porter/pkg/cnab/extensions/dependencies/v2" | ||
"github.com/yourbasic/graph" | ||
) | ||
|
||
// BundleGraph is a directed acyclic graph of a bundle and its dependencies | ||
// (which may be other bundles, or installations) It is used to resolve the | ||
// dependency order in which the bundles must be executed. | ||
type BundleGraph struct { | ||
// nodeKeys is a map from the node key to its index in nodes | ||
nodeKeys map[string]int | ||
nodes []Node | ||
} | ||
|
||
func NewBundleGraph() *BundleGraph { | ||
return &BundleGraph{ | ||
nodeKeys: make(map[string]int), | ||
} | ||
} | ||
|
||
// RegisterNode adds the specified node to the graph | ||
// returning true if the node is already present. | ||
func (g *BundleGraph) RegisterNode(node Node) bool { | ||
_, exists := g.nodeKeys[node.GetKey()] | ||
if !exists { | ||
nodeIndex := len(g.nodes) | ||
g.nodes = append(g.nodes, node) | ||
g.nodeKeys[node.GetKey()] = nodeIndex | ||
} | ||
return exists | ||
} | ||
|
||
func (g *BundleGraph) Sort() ([]Node, bool) { | ||
dag := graph.New(len(g.nodes)) | ||
for nodeIndex, node := range g.nodes { | ||
for _, depKey := range node.GetRequires() { | ||
depIndex, ok := g.nodeKeys[depKey] | ||
if !ok { | ||
panic("oops") | ||
} | ||
dag.Add(nodeIndex, depIndex) | ||
} | ||
} | ||
|
||
indices, ok := graph.TopSort(dag) | ||
if !ok { | ||
return nil, false | ||
} | ||
|
||
// Reverse the sort so that items with no dependencies are listed first | ||
count := len(indices) | ||
results := make([]Node, count) | ||
for i, nodeIndex := range indices { | ||
results[count-i-1] = g.nodes[nodeIndex] | ||
} | ||
return results, true | ||
} | ||
|
||
func (g *BundleGraph) GetNode(key string) (Node, bool) { | ||
if nodeIndex, ok := g.nodeKeys[key]; ok { | ||
return g.nodes[nodeIndex], true | ||
} | ||
return nil, false | ||
} | ||
|
||
// Node in a BundleGraph. | ||
type Node interface { | ||
GetRequires() []string | ||
GetKey() string | ||
} | ||
|
||
var _ Node = BundleNode{} | ||
var _ Node = InstallationNode{} | ||
|
||
// BundleNode is a Node in a BundleGraph that represents a dependency on a bundle | ||
// that has not yet been installed. | ||
type BundleNode struct { | ||
Key string | ||
ParentKey string | ||
Reference cnab.BundleReference | ||
Requires []string | ||
|
||
// TODO(PEP003): DO we need to store this? Can we do it somewhere else or hold a reference to the dep and add more to the Node interface? | ||
Credentials map[string]depsv2ext.DependencySource | ||
Parameters map[string]depsv2ext.DependencySource | ||
} | ||
|
||
func (d BundleNode) GetKey() string { | ||
return d.Key | ||
} | ||
|
||
func (d BundleNode) GetParentKey() string { | ||
return d.ParentKey | ||
} | ||
|
||
func (d BundleNode) GetRequires() []string { | ||
sort.Strings(d.Requires) | ||
return d.Requires | ||
} | ||
|
||
func (d BundleNode) IsRoot() bool { | ||
return d.Key == "root" | ||
} | ||
|
||
// InstallationNode is a Node in a BundleGraph that represents a dependency on an | ||
// installed bundle (installation). | ||
type InstallationNode struct { | ||
Key string | ||
ParentKey string | ||
Namespace string | ||
Name string | ||
} | ||
|
||
func (d InstallationNode) GetKey() string { | ||
return d.Key | ||
} | ||
|
||
func (d InstallationNode) GetParentKey() string { | ||
return d.ParentKey | ||
} | ||
|
||
func (d InstallationNode) GetRequires() []string { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package v2 | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestEngine_DependOnInstallation(t *testing.T) { | ||
/* | ||
A -> B (installation) | ||
A -> C (bundle) | ||
c.parameters.connstr <- B.outputs.connstr | ||
*/ | ||
|
||
b := InstallationNode{Key: "b"} | ||
c := BundleNode{ | ||
Key: "c", | ||
Requires: []string{"b"}, | ||
} | ||
a := BundleNode{ | ||
Key: "root", | ||
Requires: []string{"b", "c"}, | ||
} | ||
|
||
g := NewBundleGraph() | ||
g.RegisterNode(a) | ||
g.RegisterNode(b) | ||
g.RegisterNode(c) | ||
sortedNodes, ok := g.Sort() | ||
require.True(t, ok, "graph should not be cyclic") | ||
|
||
gotOrder := make([]string, len(sortedNodes)) | ||
for i, node := range sortedNodes { | ||
gotOrder[i] = node.GetKey() | ||
} | ||
wantOrder := []string{ | ||
"b", | ||
"c", | ||
"root", | ||
} | ||
assert.Equal(t, wantOrder, gotOrder) | ||
} | ||
|
||
/* | ||
✅ need to represent new dependency structure on an extended bundle wrapper | ||
(put in cnab-go later) | ||
need to read a bundle and make a BundleGraph | ||
? how to handle a param that isn't a pure assignment, e.g. connstr: ${bundle.deps.VM.outputs.ip}:${bundle.deps.SVC.outputs.port} | ||
? when are templates evaluated as the graph is executed (for simplicity, first draft no composition / templating) | ||
need to resolve dependencies in the graph | ||
* lookup against existing installations | ||
* lookup against semver tags in registry | ||
* lookup against bundle index? when would we look here? (i.e. preferred/registered implementations of interfaces) | ||
need to turn the sorted nodes into an execution plan | ||
execution plan needs: | ||
* bundle to execute and the installation it will become | ||
* parameters and credentials to pass | ||
* sources: | ||
root parameters/creds | ||
installation outputs | ||
need to write something that can run an execution plan | ||
* knows how to grab sources and pass them into the bundle | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package v2 | ||
|
||
import ( | ||
"context" | ||
|
||
"get.porter.sh/porter/pkg/cache" | ||
"get.porter.sh/porter/pkg/cnab" | ||
) | ||
|
||
// BundlePuller can query and pull bundles. | ||
type BundlePuller interface { | ||
// GetBundle retrieves a bundle definition. | ||
GetBundle(ctx context.Context, ref cnab.OCIReference) (cache.CachedBundle, error) | ||
|
||
// ListTags retrieves all tags defined for a bundle. | ||
ListTags(ctx context.Context, ref cnab.OCIReference) ([]string, error) | ||
} |
Oops, something went wrong.