Skip to content
Merged
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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ image:
Additionally for the best user experience and optimized sti operation we suggest image
to have `/bin/sh` and tar command inside.

Users can also set extra environment variables in the application source code,
which are passed to the build and the `assemble` script consumes them. All
environment variables are also present in the output application image. These
variables are defined in `.sti/environment` file inside the application sources.
The format of this file is a simple key-value, for example:

```
FOO=bar
```

In this case, the value of `FOO` environment variable will be set to `bar`.

For detailed description of the requirements and the scripts along with examples see
[builder_image.md](https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md)

Expand All @@ -51,6 +63,7 @@ For detailed description of the requirements and the scripts along with examples
1. `sti` creates a container based on the build image and passes it a tar file that contains:
1. The application source in `src`
1. The build artifacts in `artifacts` (if applicable - see [incremental builds](#incremental-builds))
1. `sti` sets the environment variables from `.sti/environment` (optional)
1. `sti` starts the container and runs its `assemble` script
1. `sti` waits for the container to finish
1. `sti` commits the container, setting the CMD for the output image to be the `run` script and tagging the image with the name provided.
Expand Down
5 changes: 5 additions & 0 deletions pkg/api/scripts.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ const (
SaveArtifacts = "save-artifacts"
// Usage is the name of the script responsible for printing the builder image's short info.
Usage = "usage"

// Environment contains list of key value pairs that will be set during the
// STI build. Users can use this file to provide extra configuration
// depending on the builder image used.
Environment = "environment"
)

const (
Expand Down
7 changes: 7 additions & 0 deletions pkg/build/strategies/onbuild/onbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/openshift/source-to-image/pkg/build/strategies/sti"
"github.com/openshift/source-to-image/pkg/docker"
"github.com/openshift/source-to-image/pkg/git"
"github.com/openshift/source-to-image/pkg/scripts"
"github.com/openshift/source-to-image/pkg/tar"
"github.com/openshift/source-to-image/pkg/util"
)
Expand Down Expand Up @@ -124,6 +125,12 @@ func (b *OnBuild) CreateDockerfile(request *api.Request) error {
if err != nil {
return err
}
env, err := scripts.GetEnvironment(request)
if err != nil {
glog.V(1).Infof("Environment: %v", err)
} else {
buffer.WriteString(scripts.ConvertEnvironmentToDocker(env))
}
// If there is an assemble script present, run it as part of the build process
// as the last thing.
if b.hasAssembleScript(request) {
Expand Down
18 changes: 16 additions & 2 deletions pkg/build/strategies/sti/sti.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,17 @@ func (b *STI) PostExecute(containerID string, location string) error {
}
}

env, err := scripts.GetEnvironment(b.request)
if err != nil {
glog.V(1).Infof("No .sti/environment provided (%v)", err)
}

buildEnv := append(scripts.ConvertEnvironment(env), b.generateConfigEnv()...)

cmd := []string{}
opts := docker.CommitContainerOptions{
Command: append(cmd, filepath.Join(location, api.Run)),
Env: b.generateConfigEnv(),
Env: buildEnv,
ContainerID: containerID,
Repository: b.request.Tag,
}
Expand Down Expand Up @@ -296,6 +303,13 @@ func (b *STI) Save(request *api.Request) (err error) {
func (b *STI) Execute(command string, request *api.Request) error {
glog.V(2).Infof("Using image name %s", request.BaseImage)

env, err := scripts.GetEnvironment(request)
if err != nil {
glog.V(1).Infof("No .sti/environment provided (%v)", err)
}

buildEnv := append(scripts.ConvertEnvironment(env), b.generateConfigEnv()...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens for layered builds (the case where we don't have tar)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, we should do the same as for on build. I will add that tomorrow.
On Feb 24, 2015 6:48 PM, "Ben Parees" [email protected] wrote:

In pkg/build/strategies/sti/sti.go
#145 (comment)
:

@@ -296,6 +296,13 @@ func (b *STI) Save(request *api.Request) (err error) {
func (b *STI) Execute(command string, request *api.Request) error {
glog.V(2).Infof("Using image name %s", request.BaseImage)

  • env, err := scripts.GetEnvironment(request)
  • if err != nil {
  •   glog.V(1).Infof("No .sti/environment provided (%v)", err)
    
  • }
  • buildEnv := append(scripts.ConvertEnvironment(env), b.generateConfigEnv()...)

what happens for layered builds (the case where we don't have tar)?


Reply to this email directly or view it on GitHub
https://github.com/openshift/source-to-image/pull/145/files#r25273877.


uploadDir := filepath.Join(request.WorkingDir, "upload")
tarFileName, err := b.tar.CreateTarFile(request.WorkingDir, uploadDir)
if err != nil {
Expand Down Expand Up @@ -329,7 +343,7 @@ func (b *STI) Execute(command string, request *api.Request) error {
ScriptsURL: request.ScriptsURL,
Location: request.Location,
Command: command,
Env: b.generateConfigEnv(),
Env: buildEnv,
PostExec: b.postExecutor,
}
if !request.LayeredBuild {
Expand Down
73 changes: 73 additions & 0 deletions pkg/scripts/environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package scripts

import (
"bufio"
"errors"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/golang/glog"
"github.com/openshift/source-to-image/pkg/api"
)

// Environment represents a single environment variable definition
type Environment struct {
Name string
Value string
}

// GetEnvironment gets the .sti/environment file located in the sources and
// parse it into []environment
func GetEnvironment(request *api.Request) ([]Environment, error) {
envPath := filepath.Join(request.WorkingDir, api.Source, ".sti", api.Environment)
if _, err := os.Stat(envPath); os.IsNotExist(err) {
return nil, errors.New("no evironment file found in application sources")
}

f, err := os.Open(envPath)
if err != nil {
return nil, errors.New("unable to read .sti/environment file")
}
defer f.Close()

result := []Environment{}

scanner := bufio.NewScanner(f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's really no built in properties-style parsing library for go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will check stdlib, but I'm sceptical

for scanner.Scan() {
s := scanner.Text()
// Allow for comments in environment file
if strings.HasPrefix(s, "#") {
continue
}
parts := strings.SplitN(s, "=", 2)
if len(parts) != 2 {
continue
}
e := Environment{
Name: strings.TrimSpace(parts[0]),
Value: strings.TrimSpace(parts[1]),
}
glog.V(1).Infof("Setting '%s' to '%s'", e.Name, e.Value)
result = append(result, e)
}

return result, scanner.Err()
}

// ConvertEnvironment converts the []Environment to "key=val" strings
func ConvertEnvironment(env []Environment) (result []string) {
for _, e := range env {
result = append(result, fmt.Sprintf("%s=%s", e.Name, e.Value))
}
return
}

// ConvertEnvironmentToDocker converts the []Environment into Dockerfile format
func ConvertEnvironmentToDocker(env []Environment) (result string) {
for _, e := range env {
result += fmt.Sprintf("ENV %s %s\n", e.Name, e.Value)
}
return
}
16 changes: 16 additions & 0 deletions pkg/scripts/environment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package scripts

import "testing"

func TestConvertEnvironment(t *testing.T) {
env := []Environment{
{"FOO", "BAR"},
}
result := ConvertEnvironment(env)
if len(result) != 1 {
t.Errorf("Expected 1 item, got %d", len(result))
}
if result[0] != "FOO=BAR" {
t.Errorf("Expected FOO=BAR, got %v", result)
}
}