Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Carolyn Van Slyck <me@carolynvanslyck.com>
  • Loading branch information
carolynvs committed Aug 31, 2022
1 parent d815218 commit 63215d9
Show file tree
Hide file tree
Showing 26 changed files with 1,571 additions and 44 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ require (
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.1
github.com/xeipuuv/gojsonschema v1.2.0
github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869
go.mongodb.org/mongo-driver v1.7.1
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0
go.opentelemetry.io/otel v1.7.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1578,6 +1578,8 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMx
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869 h1:7v7L5lsfw4w8iqBBXETukHo4IPltmD+mWoLRYUmeGN8=
github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869/go.mod h1:Rfzr+sqaDreiCaoQbFCu3sTXxeFq/9kXRuyOoSlGQHE=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
118 changes: 106 additions & 12 deletions pkg/cnab/config-adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package configadapter

import (
"context"
"encoding/json"
"fmt"
"path"
"regexp"
"strings"

"get.porter.sh/porter/pkg/cnab"
depsv1 "get.porter.sh/porter/pkg/cnab/dependencies/v1"
depsv2 "get.porter.sh/porter/pkg/cnab/dependencies/v2"
"get.porter.sh/porter/pkg/config"
"get.porter.sh/porter/pkg/experimental"
"get.porter.sh/porter/pkg/manifest"
Expand All @@ -16,6 +19,7 @@ import (
"github.com/Masterminds/semver/v3"
"github.com/cnabio/cnab-go/bundle"
"github.com/cnabio/cnab-go/bundle/definition"
"github.com/pkg/errors"
)

// ManifestConverter converts from a porter manifest to a CNAB bundle definition.
Expand Down Expand Up @@ -408,33 +412,33 @@ func (c *ManifestConverter) generateBundleImages() map[string]bundle.Image {
}

func (c *ManifestConverter) generateDependencies() (interface{}, string, error) {
if len(c.Manifest.Dependencies.RequiredDependencies) == 0 {
if len(c.Manifest.Dependencies.Requires) == 0 {
return nil, "", nil
}

// Check if they are using v1 of the dependencies spec or v2
if c.config.IsFeatureEnabled(experimental.FlagDependenciesV2) {
panic("the dependencies-v2 experimental flag was specified but is not yet implemented")
// Ok we are using v2!
deps, err := c.generateDependenciesV2()
return deps, cnab.DependenciesV2ExtensionKey, err
}

deps, err := c.generateDependenciesV1()
if err != nil {
return nil, "", err
}
// Default to using v1 of deps
deps := c.generateDependenciesV1()
return deps, cnab.DependenciesV1ExtensionKey, nil
}

func (c *ManifestConverter) generateDependenciesV1() (*depsv1.Dependencies, error) {
if len(c.Manifest.Dependencies.RequiredDependencies) == 0 {
return nil, nil
func (c *ManifestConverter) generateDependenciesV1() *depsv1.Dependencies {
if len(c.Manifest.Dependencies.Requires) == 0 {
return nil
}

deps := &depsv1.Dependencies{
Sequence: make([]string, 0, len(c.Manifest.Dependencies.RequiredDependencies)),
Requires: make(map[string]depsv1.Dependency, len(c.Manifest.Dependencies.RequiredDependencies)),
Sequence: make([]string, 0, len(c.Manifest.Dependencies.Requires)),
Requires: make(map[string]depsv1.Dependency, len(c.Manifest.Dependencies.Requires)),
}

for _, dep := range c.Manifest.Dependencies.RequiredDependencies {
for _, dep := range c.Manifest.Dependencies.Requires {
dependencyRef := depsv1.Dependency{
Name: dep.Name,
Bundle: dep.Bundle.Reference,
Expand All @@ -454,9 +458,97 @@ func (c *ManifestConverter) generateDependenciesV1() (*depsv1.Dependencies, erro
deps.Requires[dep.Name] = dependencyRef
}

return deps
}

func (c *ManifestConverter) generateDependenciesV2() (*depsv2.Dependencies, error) {
deps := &depsv2.Dependencies{
Requires: make(map[string]depsv2.Dependency, len(c.Manifest.Dependencies.Requires)),
}

for _, dep := range c.Manifest.Dependencies.Requires {
dependencyRef := depsv2.Dependency{
Name: dep.Name,
Bundle: dep.Bundle.Reference,
Version: dep.Bundle.Version,
}

if dep.Bundle.Interface != nil {
if dep.Bundle.Interface.Reference != "" {
dependencyRef.Interface.Reference = dep.Bundle.Interface.Reference
}
if dep.Bundle.Interface.Document != nil {
bundleData, err := json.Marshal(dep.Bundle.Interface.Document)
if err != nil {
return nil, errors.Wrapf(err, "invalid bundle interface document for dependency %s", dep.Name)
}
rawMessage := &json.RawMessage{}
err = rawMessage.UnmarshalJSON(bundleData)
if err != nil {
return nil, errors.Wrapf(err, "could not convert bundle interface document to a raw json message for dependency %s", dep.Name)
}
dependencyRef.Interface.Document = rawMessage
}
}

if dep.Installation != nil {
dependencyRef.Installation = &depsv2.DependencyInstallation{
Labels: dep.Installation.Labels,
}
if dep.Installation.Criteria != nil {
dependencyRef.Installation.Criteria = &depsv2.InstallationCriteria{
MatchInterface: dep.Installation.Criteria.MatchInterface,
MatchNamespace: dep.Installation.Criteria.MatchNamespace,
IgnoreLabels: dep.Installation.Criteria.IgnoreLabels,
}
}
}

if len(dep.Parameters) > 0 {
dependencyRef.Parameters = make(map[string]depsv2.DependencySource, len(dep.Parameters))
for param, source := range dep.Parameters {
dependencyRef.Parameters[param] = parseDependencySource(source)
}
}

if len(dep.Credentials) > 0 {
dependencyRef.Credentials = make(map[string]depsv2.DependencySource, len(dep.Credentials))
for cred, source := range dep.Credentials {
dependencyRef.Credentials[cred] = parseDependencySource(source)
}
}

deps.Requires[dep.Name] = dependencyRef
}

return deps, nil
}

// TODO: is there a way to feature flag this stuff so that if it's flakey or implemented
// incrementally we can just keep it off?
func parseDependencySource(value string) depsv2.DependencySource {
regex := regexp.MustCompile(`bundle(\.dependencies)?\.([^.]+)\.([^.]+)\.(.+)`)
matches := regex.FindStringSubmatch(value)
if matches == nil || len(matches) < 5 {
return depsv2.DependencySource{Value: value}
}

dependencyName := matches[2] // bundle.dependencies.DEPENDENCY_NAME
itemType := matches[3] // bundle.dependencies.dependency_name.PARAMETERS.name or bundle.OUTPUTS.name
itemName := matches[4] // bundle.dependencies.dependency_name.parameters.NAME or bundle.outputs.NAME

result := depsv2.DependencySource{Dependency: dependencyName}
switch itemType {
case "parameters":
result.Parameter = itemName
case "credentials":
result.Credential = itemName
case "outputs":
result.Output = itemName
}
return result
}

func (c *ManifestConverter) generateParameterSources(b *cnab.ExtendedBundle) cnab.ParameterSources {
ps := cnab.ParameterSources{}

Expand Down Expand Up @@ -643,6 +735,8 @@ func (c *ManifestConverter) generateRequiredExtensions(b cnab.ExtendedBundle) []
// Add the appropriate dependencies key if applicable
if b.HasDependenciesV1() {
requiredExtensions = append(requiredExtensions, cnab.DependenciesV1ExtensionKey)
} else if b.HasDependenciesV2() {
requiredExtensions = append(requiredExtensions, cnab.DependenciesV2ExtensionKey)
}

// Add the appropriate parameter sources key if applicable
Expand Down
45 changes: 45 additions & 0 deletions pkg/cnab/config-adapter/testdata/porter-depsv2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
schemaVersion: 1.0.0-alpha.1
name: porter-hello
description: "An example Porter configuration"
version: 0.1.0
registry: "localhost:5000"

credentials:
- name: username
description: Name of the database user
required: false
env: ROOT_USERNAME
- name: password
path: /tmp/password
applyTo:
- uninstall

dependencies:
requires:
- name: mysql
bundle:
reference: "getporter/azure-mysql:5.7"

mixins:
- exec

install:
- exec:
description: "Say Hello"
command: bash
flags:
c: echo Hello World

status:
- exec:
description: "Get World Status"
command: bash
flags:
c: echo The world is on fire

uninstall:
- exec:
description: "Say Goodbye"
command: bash
flags:
c: echo Goodbye World
78 changes: 78 additions & 0 deletions pkg/cnab/dependencies/v2/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package v2

import (
"encoding/json"
)

// Dependencies describes the set of custom extension metadata associated with the dependencies spec
// https://github.com/cnabio/cnab-spec/blob/master/500-CNAB-dependencies.md
type Dependencies struct {
// Requires is a list of bundles required by this bundle
Requires map[string]Dependency `json:"requires,omitempty" mapstructure:"requires"`
}

/*
dependencies:
requires: # dependencies are always created in the current namespace, never global though they can match globally?
mysql:
bundle:
reference: getporter/mysql:v1.0.2
version: 1.x
interface: # Porter defaults the interface based on usage
reference: getporter/generic-mysql-interface:v1.0.0 # point to an interface bundle to be more specific
bundle: # add extra interface requirements
outputs:
- $id: "mysql-5.7-connection-string" # match on something other than name, so that outputs with different names can be reused
installation:
labels: # labels applied to the installation if created
app: myapp
installation: {{ installation.name }} # exclusive resource
criteria: # criteria for reusing an existing installation, by default must be the same bundle, labels and allows global
matchInterface: true # only match the interface, not the bundle too
matchNamespace: true # must be in the same namespace, disallow global
ignoreLabels: true # allow different labels
*/

// Dependency describes a dependency on another bundle
type Dependency struct {
// Name of the dependency
Name string

// Bundle is the location of the bundle in a registry, for example REGISTRY/NAME:TAG
Bundle string `json:"bundle" mapstructure:"bundle"`

// Version is a set of allowed versions
Version string `json:"version,omitempty" mapstructure:"version"`

Interface *DependencyInterface `json:"interface,omitempty" mapstructure:"interface,omitempty"`

Installation *DependencyInstallation `json:"installation,omitempty" mapstructure:"installation,omitempty"`

Parameters map[string]DependencySource `json:"parameters,omitempty" mapstructure:"parameters,omitempty"`
Credentials map[string]DependencySource `json:"credentials,omitempty" mapstructure:"credentials,omitempty"`
}

type DependencySource struct {
Value string `json:"value,omitempty" mapstructure:"value,omitempty"`
Dependency string `json:"dependency,omitempty" mapstructure:"dependency,omitempty"`
Credential string `json:"credential,omitempty" mapstructure:"credential,omitempty"`
Parameter string `json:"parameter,omitempty" mapstructure:"parameter,omitempty"`
Output string `json:"output,omitempty" mapstructure:"output,omitempty"`
}

type DependencyInstallation struct {
Labels map[string]string `json:"labels,omitempty" mapstructure:"labels,omitempty"`
Criteria *InstallationCriteria `json:"criteria,omitempty" mapstructure:"criteria,omitempty"`
}

type InstallationCriteria struct {
// MatchInterface specifies if the installation should use the same bundle or just needs to match the interface
MatchInterface bool `json:"matchInterface,omitempty" mapstructure:"matchInterface,omitEmpty"`
MatchNamespace bool `json:"matchNamespace,omitempty" mapstructure:"matchNamespace,omitEmpty"`
IgnoreLabels bool `json:"ignoreLabels,omitempty" mapstructure:"ignoreLabels,omitempty"`
}

type DependencyInterface struct {
Reference string `json:"reference,omitempty" mapstructure:"reference,omitempty"`
Document *json.RawMessage `json:"document,omitempty" mapstructure:"document,omitempty"`
}
Loading

0 comments on commit 63215d9

Please sign in to comment.