Skip to content

Commit

Permalink
Create a new parameter type, and refactor parameter type checking int…
Browse files Browse the repository at this point in the history
…o its own function to facilitate additional growth.

Signed-off-by: Rich Baird <[email protected]>
  • Loading branch information
Rich Baird authored and Rich Baird committed Jul 25, 2022
1 parent a744f47 commit f26bba5
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 10 deletions.
Binary file added go1.18.3.linux-amd64.tar.gz
Binary file not shown.
16 changes: 8 additions & 8 deletions pkg/cnab/config-adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package configadapter
import (
"context"
"fmt"
"os"
"path"
"strings"

Expand Down Expand Up @@ -196,8 +197,11 @@ func (c *ManifestConverter) generateBundleParameters(ctx context.Context, defs *
}

if param.Type == nil {
// Default to a file type if the param is stored in a file
if param.Destination.Path != "" {
// Default to a directory type if the param is a directory
if param.Destination.Path != "" && strings.HasSuffix(param.Destination.Path, string(os.PathSeparator)) {
param.Type = "directory"
} else if param.Destination.Path != "" {
// If the path could refer to a file assume that it does unless specified explicity
param.Type = "file"
} else {
// Assume it's a string otherwise
Expand Down Expand Up @@ -291,12 +295,8 @@ func (c *ManifestConverter) addDefinition(name string, kind string, def definiti
defName = name + "-" + kind
}

// file is a porter specific type, swap it out for something CNAB understands
if def.Type == "file" {
def.Type = "string"
def.ContentEncoding = "base64"
}

// Type may be a porter specific type, swap it out for something CNAB understands
MakeCNABCompatible(&def)
(*defs)[defName] = &def

return defName
Expand Down
11 changes: 11 additions & 0 deletions pkg/cnab/config-adapter/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"get.porter.sh/porter/pkg/cnab"
"get.porter.sh/porter/pkg/config"
"get.porter.sh/porter/pkg/manifest"
"github.com/cnabio/cnab-go/bundle/definition"
)

// ConvertToTestBundle is suitable for taking a test manifest (porter.yaml)
Expand All @@ -15,3 +16,13 @@ func ConvertToTestBundle(ctx context.Context, cfg *config.Config, manifest *mani
converter := NewManifestConverter(cfg, manifest, nil, nil)
return converter.ToBundle(ctx)
}


func MakeCNABCompatible(schema *definition.Schema) {
if v, ok := schema.Type.(string); ok {
if t, ok := config.PorterParamMap[v]; ok {
schema.Type = t;
schema.ContentEncoding = "base64"
}
}
}
7 changes: 7 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ const (
EnvPorterInstallationName = "PORTER_INSTALLATION_NAME"
)

// PorterParamMap maps custom porter parameter types to a CNAB compatible alternative
var PorterParamMap = map[string]string {
"file": "string",
"directory": "string",
}


// These are functions that afero doesn't support, so this lets us stub them out for tests to set the
// location of the current executable porter binary and resolve PORTER_HOME.
var getExecutable = os.Executable
Expand Down
16 changes: 16 additions & 0 deletions pkg/manifest/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package manifest

import "get.porter.sh/porter/pkg/config"

func MakeCNABCompatible(def *ParameterDefinition) bool {
if v, ok := def.Type.(string); ok {
if t, ok := config.PorterParamMap[v]; ok {
def.Type = t
def.ContentEncoding = "base64"

return ok
}
}

return false
}
6 changes: 4 additions & 2 deletions pkg/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,13 @@ func (pd *ParameterDefinition) Validate() error {
result = multierror.Append(result, errors.New("parameter name is required"))
}

// Porter supports declaring a parameter of type: "file",
// Porter supports declaring a parameter of types: "file" and "directory",
// which we will convert to the appropriate bundle.Parameter type in adapter.go
// Here, we copy the ParameterDefinition and make the same modification before validation
pdCopy := pd.DeepCopy()
if pdCopy.Type == "file" {
if MakeCNABCompatible(pdCopy) {
// TODO: Currently all custom parameter types require a path property. This may not be the case in the future,
// Instead, we should do the validation separately for each type.
if pd.Destination.Path == "" {
result = multierror.Append(result, fmt.Errorf("no destination path supplied for parameter %s", pd.Name))
}
Expand Down
242 changes: 242 additions & 0 deletions scratch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package main

import (
"encoding/json"
"fmt"
"os"
)

// Type represents the type of a mount.
type Type string

// Type constants
const (
// TypeBind is the type for mounting host dir
TypeBind Type = "bind"
// TypeVolume is the type for remote storage volumes
TypeVolume Type = "volume"
// TypeTmpfs is the type for mounting tmpfs
TypeTmpfs Type = "tmpfs"
// TypeNamedPipe is the type for mounting Windows named pipes
TypeNamedPipe Type = "npipe"
)

// Mount represents a mount (volume).
type Mount struct {
Type Type `json:""`
// Source specifies the name of the mount. Depending on mount type, this
// may be a volume name or a host path, or even ignored.
// Source is not supported for tmpfs (must be an empty value)
Source string `json:""`
Target string `json:""`
ReadOnly bool `json:""`
Consistency Consistency `json:""`

BindOptions *BindOptions `json:""`
VolumeOptions *VolumeOptions `json:""`
TmpfsOptions *TmpfsOptions `json:""`
}

// Propagation represents the propagation of a mount.
type Propagation string

const (
// PropagationRPrivate RPRIVATE
PropagationRPrivate Propagation = "rprivate"
// PropagationPrivate PRIVATE
PropagationPrivate Propagation = "private"
// PropagationRShared RSHARED
PropagationRShared Propagation = "rshared"
// PropagationShared SHARED
PropagationShared Propagation = "shared"
// PropagationRSlave RSLAVE
PropagationRSlave Propagation = "rslave"
// PropagationSlave SLAVE
PropagationSlave Propagation = "slave"
)

// Propagations is the list of all valid mount propagations
var Propagations = []Propagation{
PropagationRPrivate,
PropagationPrivate,
PropagationRShared,
PropagationShared,
PropagationRSlave,
PropagationSlave,
}

// Consistency represents the consistency requirements of a mount.
type Consistency string

const (
// ConsistencyFull guarantees bind mount-like consistency
ConsistencyFull Consistency = "consistent"
// ConsistencyCached mounts can cache read data and FS structure
ConsistencyCached Consistency = "cached"
// ConsistencyDelegated mounts can cache read and written data and structure
ConsistencyDelegated Consistency = "delegated"
// ConsistencyDefault provides "consistent" behavior unless overridden
ConsistencyDefault Consistency = "default"
)

// BindOptions defines options specific to mounts of type "bind".
type BindOptions struct {
Propagation Propagation `json:""`
NonRecursive bool `json:""`
}

// VolumeOptions represents the options for a mount of type volume.
type VolumeOptions struct {
NoCopy bool `json:""`
Labels map[string]string `json:""`
DriverConfig *Driver `json:""`
}

// Driver represents a volume driver.
type Driver struct {
Name string `json:""`
Options map[string]string `json:""`
}

// TmpfsOptions defines options specific to mounts of type "tmpfs".
type TmpfsOptions struct {
// Size sets the size of the tmpfs, in bytes.
//
// This will be converted to an operating system specific value
// depending on the host. For example, on linux, it will be converted to
// use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with
// docker, uses a straight byte value.
//
// Percentages are not supported.
SizeBytes int64 `json:""`
// Mode of the tmpfs upon creation
Mode os.FileMode `json:""`

// TODO(stevvooe): There are several more tmpfs flags, specified in the
// daemon, that are accepted. Only the most basic are added for now.
//
// From https://github.com/moby/sys/blob/mount/v0.1.1/mount/flags.go#L47-L56
//
// var validFlags = map[string]bool{
// "": true,
// "size": true, X
// "mode": true, X
// "uid": true,
// "gid": true,
// "nr_inodes": true,
// "nr_blocks": true,
// "mpol": true,
// }
//
// Some of these may be straightforward to add, but others, such as
// uid/gid have implications in a clustered system.
}

type PortBinding struct {
// HostIP is the host IP Address
HostIP string `json:"HostIp"`
// HostPort is the host port number
HostPort string
}

// PortMap is a collection of PortBinding indexed by Port
type PortMap map[Port][]PortBinding

// PortSet is a collection of structs indexed by Port
type PortSet map[Port]struct{}

// Port is a string containing port number and protocol in the format "80/tcp"
type Port string

// RestartPolicy represents the restart policies of the container.
type RestartPolicy struct {
Name string
MaximumRetryCount int
}

// Docker describes the set of custom extension metadata associated with the Docker extension
type Docker struct {
// Privileged represents whether or not the Docker container should run as --privileged
Privileged bool `json:"privileged"`
// Mounts represent mounts to be attached to the host machine with all configurable options.
Mounts []Mount `json:"mounts"`
// Network represents the network type applied to the container "host,bridged,etc"
Network string `json:"network"`
// CapAdd represents the capabilities available to the container kernel
CapAdd []string `json:"capadd"`
// CapDrop represents capabilities to exclude from the container kernel
CapDrop []string `json:"capdrop"`
// Ports to bind between the host and the container
PortBindings []PortMap `json:"portBindings"`
// Restart policy to be used for the container
// This may be useful in some rare cases
RestartPolicy RestartPolicy `json:"restartPolicy"`
}

func PrettyStruct(data interface{}) (string, error) {
val, err := json.MarshalIndent(data, "", " ")
if err != nil {
return "", err
}
return string(val), nil
}

func main() {
docker := Docker{
Privileged: false,
Mounts: []Mount{
{
Type: "",
Source: "",
Target: "",
ReadOnly: false,
Consistency: "",
BindOptions: &BindOptions{
Propagation: "",
NonRecursive: false,
},
VolumeOptions: &VolumeOptions{
NoCopy: false,
Labels: map[string]string{
"": "",
},
DriverConfig: &Driver{
Name: "",
Options: map[string]string{
"": "",
},
},
},
TmpfsOptions: &TmpfsOptions{
SizeBytes: 0,
Mode: 0,
},
},
},
Network: "",
CapAdd: []string{
"c1",
"c2",
},
CapDrop: []string{
"c3",
"c4",
},
PortBindings: []PortMap{
{
"80": []PortBinding{
{
HostIP: "0.0.0.0",
HostPort: "8080",
},
},
},
},
RestartPolicy: RestartPolicy{
Name: "",
MaximumRetryCount: 0,
},
}

fmt.Println(PrettyStruct(docker))
}
Loading

0 comments on commit f26bba5

Please sign in to comment.