Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions pkg/template/example/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
{
"id": "example1",
"name": "my-awesome-php-app",
"description": "Example PHP application with PostgreSQL database",
"buildConfig": [
{
"name": "mfojtik/nginx-php-app",
"type": "docker",
"sourceUri": "https://raw.githubusercontent.com/mfojtik/phpapp/master/Dockerfile",
"imageRepository": "int.registry.com:5000/mfojtik/phpapp"
},
{
"name": "postgres",
"type": "docker",
"imageRepository": "registry.hub.docker.com/postgres",
"sourceUri": "https://raw.githubusercontent.com/docker-library/postgres/docker/9.2/Dockerfile"
}
],
"imageRepository": [
{
"name": "mfojtik/nginx-php-app",
"url": "internal.registry.com:5000/mfojtik/phpapp"
},
{
"name": "postgres",
"url": "registry.hub.docker.com/postgres"
}
],
"parameters": [
{
"name": "DB_PASSWORD",
"description": "PostgreSQL admin user password",
"type": "string",
"generate": "[a-zA-Z0-9]{8}"
},
{
"name": "DB_USER",
"description": "PostgreSQL username",
"type": "string",
"generate": "admin[a-zA-Z0-9]{4}"
},
{
"name": "DB_NAME",
"description": "PostgreSQL database name",
"type": "string",
"generate": "[GET:http://broken.url/test]"
},
{
"name": "SAMPLE_VAR",
"description": "Sample",
"type": "string",
"value": "foo"
}
],
"serviceLinks": [
{
"from": "database",
"export": [
{
"name": "POSTGRES_ADMIN_USERNAME",
"value": "${DB_USER}"
},
{
"name": "POSTGRES_ADMIN_PASSWORD",
"value": "${DB_PASSWORD}"
},
{
"name": "POSTGRES_DATABASE_NAME",
"value": "${DB_NAME}"
}
],
"to": "frontend"
}
],
"services": [
{
"name": "database",
"description": "Standalone PostgreSQL 9.2 database service",
"labels": {
"name": "database-service"
},
"deploymentConfig": {
"deployment": {
"podTemplate": {
"containers": [
{
"name": "postgresql-1",
"image": {
"name": "postgres",
"tag": "9.2"
},
"env": [
{
"name": "POSTGRES_ADMIN_USERNAME",
"value": "${DB_USER}"
},
{
"name": "POSTGRES_ADMIN_PASSWORD",
"value": "${DB_PASSWORD}"
},
{
"name": "POSTGRES_DATABASE_NAME",
"value": "${DB_NAME}"
},
{
"name": "FOO",
"value": "${BAR}"
}
],
"ports": [
{
"containerPort": 5432,
"hostPort": 5432
}
]
}
]
}
}
}
},
{
"name": "frontend",
"description": "Sample PHP 5.2 application served by NGINX",
"labels": {
"name": "frontend-service"
},
"deploymentConfig": {
"deployment": {
"podTemplate": {
"containers": [
{
"name": "nginx-php-app",
"hooks": {
"prestart": {
"cmd": "import_database.sh"
},
"url": "git://github.com/user/myapp-hooks.git"
},
"image": {
"name": "mfojtik/nginx-php-app",
"tag": "latest"
},
"ports": [
{
"containerPort": 8080,
"hostPort": 8080
}
]
}
]
}
}
}
}
]
}
121 changes: 121 additions & 0 deletions pkg/template/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package template

import (
"fmt"
"math/rand"
"regexp"
"strings"

"github.com/openshift/origin/pkg/template/generator"
)

var valueExp = regexp.MustCompile(`(\$\{([a-zA-Z0-9\_]+)\})`)

type ParamHash map[string]Parameter

// Generate the value for the Parameter if the default Value is not set and the
// Generator field is specified. Otherwise, just return the default Value
func (p *Parameter) GenerateValue() error {
if p.Value != "" || p.Generate == "" {
return nil
}

g := generator.Generator{}
generatedValue, err := g.Generate(p.Generate).Value()

if err != nil {
return err
}
p.Value = generatedValue

return nil
}

// The string representation of PValue
//
func (s PValue) String() string {
return string(s)
}

// Replace references to parameters in PValue with their values.
// The format is specified in the `valueExp` constant ${PARAM_NAME}.
//
// If the referenced parameter is not defined, then the substitution is ignored.
func (s *PValue) Substitute(params ParamHash) {
newValue := *s

for _, match := range valueExp.FindAllStringSubmatch(string(newValue), -1) {
// If the Parameter is not defined, then leave the value as it is
if params[match[2]].Value == "" {
continue
}
newValue = PValue(strings.Replace(string(newValue), match[1], params[match[2]].Value, 1))
}

*s = newValue
}

// Generate Value field for defined Parameters.
// If the Parameter define Generate, then the Value is generated based
// on that template. The template is a pseudo-regexp formatted string.
//
// Example:
//
// s := generate.Template("[a-zA-Z0-9]{4}")
// // s: "Ga0b"
//
// s := generate.Template("[GET:http://example.com/new]")
// // s: <body from the GET request>
func (p *Template) ProcessParameters() {
rand.Seed(p.RandomSeed)

for i, _ := range p.Parameters {
if err := p.Parameters[i].GenerateValue(); err != nil {
fmt.Printf("ERROR: Unable to process parameter %s: %v\n", p.Parameters[i].Name, err)
p.Parameters[i].Value = p.Parameters[i].Generate
}
}
}

// A shorthand method to get list of *all* container defined in the Template
// template
func (p *Template) Containers() []*Container {
var result []*Container
for _, s := range p.Services {
result = append(result, s.Containers()...)
}
return result
}

// Convert Parameter slice to more effective data structure
func (p *Template) ParameterHash() ParamHash {
paramHash := make(ParamHash)
for _, p := range p.Parameters {
paramHash[p.Name] = p
}
return paramHash
}

// Process all Env variables in the Project template and replace parameters
// referenced in their values with the Parameter values.
//
// The replacement is done in Containers and ServiceLinks.
func (p *Template) SubstituteEnvValues() {

params := p.ParameterHash()

for _, container := range p.Containers() {
(*container).Env.Process(params)
}

for s, _ := range p.ServiceLinks {
p.ServiceLinks[s].Export.Process(params)
}
}

// Substitute referenced parameters in Env values with parameter values.
func (e *Env) Process(params ParamHash) {
for i, _ := range *e {
(*e)[i].Value.Substitute(params)
}
}
26 changes: 26 additions & 0 deletions pkg/template/generator/from_url.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package generator

import (
"io/ioutil"
"net/http"
"strings"
)

func httpGet(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
return string(body), err
}

func replaceUrlWithData(s *string, expresion string) error {
result, err := httpGet(expresion[5 : len(expresion)-1])
if err != nil {
return err
}
*s = strings.Replace(*s, expresion, strings.TrimSpace(result), 1)
return nil
}
34 changes: 34 additions & 0 deletions pkg/template/generator/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package generator

import "fmt"

type GeneratorType interface {
Value() (string, error)
}

type ExpresionGenerator struct {
expr string
}

func (g ExpresionGenerator) Value() (string, error) {
return FromTemplate(g.expr)
}

type PasswordGenerator struct {
length int
}

func (g PasswordGenerator) Value() (string, error) {
return FromTemplate(fmt.Sprintf("[\\a]{%d}", g.length))
}

type Generator struct{}

func (g Generator) Generate(t string) GeneratorType {
switch t {
case "password":
return PasswordGenerator{length: 8}
default:
return ExpresionGenerator{expr: t}
}
}
Loading