mirror of
https://github.com/openshift/source-to-image.git
synced 2026-02-05 12:44:54 +01:00
577 lines
19 KiB
Go
577 lines
19 KiB
Go
package api
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
utilglog "github.com/openshift/source-to-image/pkg/util/glog"
|
|
|
|
"github.com/openshift/source-to-image/pkg/util/user"
|
|
)
|
|
|
|
var glog = utilglog.StderrLog
|
|
|
|
// Image label namespace constants
|
|
const (
|
|
DefaultNamespace = "io.openshift.s2i."
|
|
KubernetesNamespace = "io.k8s."
|
|
)
|
|
|
|
// invalidFilenameCharacters contains a list of character we consider malicious
|
|
// when injecting the directories into containers.
|
|
const invalidFilenameCharacters = `;*?"<>|%#$!+{}&[],"'` + "`"
|
|
|
|
const (
|
|
// PullAlways means that we always attempt to pull the latest image.
|
|
PullAlways PullPolicy = "always"
|
|
|
|
// PullNever means that we never pull an image, but only use a local image.
|
|
PullNever PullPolicy = "never"
|
|
|
|
// PullIfNotPresent means that we pull if the image isn't present on disk.
|
|
PullIfNotPresent PullPolicy = "if-not-present"
|
|
|
|
// DefaultBuilderPullPolicy specifies the default pull policy to use
|
|
DefaultBuilderPullPolicy = PullIfNotPresent
|
|
|
|
// DefaultRuntimeImagePullPolicy specifies the default pull policy to use.
|
|
DefaultRuntimeImagePullPolicy = PullIfNotPresent
|
|
|
|
// DefaultPreviousImagePullPolicy specifies policy for pulling the previously
|
|
// build Docker image when doing incremental build
|
|
DefaultPreviousImagePullPolicy = PullIfNotPresent
|
|
)
|
|
|
|
// Config contains essential fields for performing build.
|
|
type Config struct {
|
|
// DisplayName is a result image display-name label. This defaults to the
|
|
// output image name.
|
|
DisplayName string
|
|
|
|
// Description is a result image description label. The default is no
|
|
// description.
|
|
Description string
|
|
|
|
// BuilderImage describes which image is used for building the result images.
|
|
BuilderImage string
|
|
|
|
// BuilderImageVersion provides optional version information about the builder image.
|
|
BuilderImageVersion string
|
|
|
|
// BuilderBaseImageVersion provides optional version information about the builder base image.
|
|
BuilderBaseImageVersion string
|
|
|
|
// RuntimeImage specifies the image that will be a base for resulting image
|
|
// and will be used for running an application. By default, BuilderImage is
|
|
// used for building and running, but the latter may be overridden.
|
|
RuntimeImage string
|
|
|
|
// RuntimeImagePullPolicy specifies when to pull a runtime image.
|
|
RuntimeImagePullPolicy PullPolicy
|
|
|
|
// RuntimeAuthentication holds the authentication information for pulling the
|
|
// runtime Docker images from private repositories.
|
|
RuntimeAuthentication AuthConfig
|
|
|
|
// RuntimeArtifacts specifies a list of source/destination pairs that will
|
|
// be copied from builder to a runtime image. Source can be a file or
|
|
// directory. Destination must be a directory. Regardless whether it
|
|
// is an absolute or relative path, it will be placed into image's WORKDIR.
|
|
// Destination also can be empty or equals to ".", in this case it just
|
|
// refers to a root of WORKDIR.
|
|
// In case it's empty, S2I will try to get this list from
|
|
// io.openshift.s2i.assemble-input-files label on a RuntimeImage.
|
|
RuntimeArtifacts VolumeList
|
|
|
|
// DockerConfig describes how to access host docker daemon.
|
|
DockerConfig *DockerConfig
|
|
|
|
// DockerCfgPath provides the path to the .dockercfg file
|
|
DockerCfgPath string
|
|
|
|
// PullAuthentication holds the authentication information for pulling the
|
|
// Docker images from private repositories
|
|
PullAuthentication AuthConfig
|
|
|
|
// IncrementalAuthentication holds the authentication information for pulling the
|
|
// previous image from private repositories
|
|
IncrementalAuthentication AuthConfig
|
|
|
|
// DockerNetworkMode is used to set the docker network setting to --net=container:<id>
|
|
// when the builder is invoked from a container.
|
|
DockerNetworkMode DockerNetworkMode
|
|
|
|
// PreserveWorkingDir describes if working directory should be left after processing.
|
|
PreserveWorkingDir bool
|
|
|
|
// IgnoreSubmodules determines whether we will attempt to pull in submodules
|
|
// (via --recursive or submodule init)
|
|
IgnoreSubmodules bool
|
|
|
|
// Source URL describing the location of sources used to build the result image.
|
|
Source string
|
|
|
|
// Ref is a tag/branch to be used for build.
|
|
Ref string
|
|
|
|
// Tag is a result image tag name.
|
|
Tag string
|
|
|
|
// BuilderPullPolicy specifies when to pull the builder image
|
|
BuilderPullPolicy PullPolicy
|
|
|
|
// PreviousImagePullPolicy specifies when to pull the previously build image
|
|
// when doing incremental build
|
|
PreviousImagePullPolicy PullPolicy
|
|
|
|
// ForcePull defines if the builder image should be always pulled or not.
|
|
// This is now deprecated by BuilderPullPolicy and will be removed soon.
|
|
// Setting this to 'true' equals setting BuilderPullPolicy to 'PullAlways'.
|
|
// Setting this to 'false' equals setting BuilderPullPolicy to 'PullIfNotPresent'
|
|
ForcePull bool
|
|
|
|
// Incremental describes whether to try to perform incremental build.
|
|
Incremental bool
|
|
|
|
// IncrementalFromTag sets an alternative image tag to look for existing
|
|
// artifacts. Tag is used by default if this is not set.
|
|
IncrementalFromTag string
|
|
|
|
// RemovePreviousImage describes if previous image should be removed after successful build.
|
|
// This applies only to incremental builds.
|
|
RemovePreviousImage bool
|
|
|
|
// Environment is a map of environment variables to be passed to the image.
|
|
Environment EnvironmentList
|
|
|
|
// EnvironmentFile provides the path to a file with list of environment
|
|
// variables.
|
|
EnvironmentFile string
|
|
|
|
// LabelNamespace provides the namespace under which the labels will be generated.
|
|
LabelNamespace string
|
|
|
|
// CallbackURL is a URL which is called upon successful build to inform about that fact.
|
|
CallbackURL string
|
|
|
|
// ScriptsURL is a URL describing the localization of S2I scripts used during build process.
|
|
ScriptsURL string
|
|
|
|
// Destination specifies a location where the untar operation will place its artifacts.
|
|
Destination string
|
|
|
|
// WorkingDir describes temporary directory used for downloading sources, scripts and tar operations.
|
|
WorkingDir string
|
|
|
|
// WorkingSourceDir describes the subdirectory off of WorkingDir set up during the repo download
|
|
// that is later used as the root for ignore processing
|
|
WorkingSourceDir string
|
|
|
|
// LayeredBuild describes if this is build which layered scripts and sources on top of BuilderImage.
|
|
LayeredBuild bool
|
|
|
|
// Operate quietly. Progress and assemble script output are not reported, only fatal errors.
|
|
// (default: false).
|
|
Quiet bool
|
|
|
|
// ForceCopy results in only the file SCM plugin being used (i.e. no `git clone`); allows for empty directories to be included
|
|
// in resulting image (since git does not support that).
|
|
// (default: false).
|
|
ForceCopy bool
|
|
|
|
// Specify a relative directory inside the application repository that should
|
|
// be used as a root directory for the application.
|
|
ContextDir string
|
|
|
|
// AllowedUIDs is a list of user ranges of users allowed to run the builder image.
|
|
// If a range is specified and the builder (or runtime) image uses a non-numeric
|
|
// user or a user that is outside the specified range, then the build fails.
|
|
AllowedUIDs user.RangeList
|
|
|
|
// AssembleUser specifies the user to run the assemble script in container
|
|
AssembleUser string
|
|
|
|
// RunImage will trigger a "docker run ..." invocation of the produced image so the user
|
|
// can see if it operates as he would expect
|
|
RunImage bool
|
|
|
|
// Usage allows for properly shortcircuiting s2i logic when `s2i usage` is invoked
|
|
Usage bool
|
|
|
|
// Injections specifies a list source/destination folders that are injected to
|
|
// the container that runs assemble.
|
|
// All files we inject will be truncated after the assemble script finishes.
|
|
Injections VolumeList
|
|
|
|
// CGroupLimits describes the cgroups limits that will be applied to any containers
|
|
// run by s2i.
|
|
CGroupLimits *CGroupLimits
|
|
|
|
// DropCapabilities contains a list of capabilities to drop when executing containers
|
|
DropCapabilities []string
|
|
|
|
// ScriptDownloadProxyConfig optionally specifies the http and https proxy
|
|
// to use when downloading scripts
|
|
ScriptDownloadProxyConfig *ProxyConfig
|
|
|
|
// ExcludeRegExp contains a string representation of the regular expression desired for
|
|
// deciding which files to exclude from the tar stream
|
|
ExcludeRegExp string
|
|
|
|
// BlockOnBuild prevents s2i from performing a docker build operation
|
|
// if one is necessary to execute ONBUILD commands, or to layer source code into
|
|
// the container for images that don't have a tar binary available, if the
|
|
// image contains ONBUILD commands that would be executed.
|
|
BlockOnBuild bool
|
|
|
|
// HasOnBuild will be set to true if the builder image contains ONBUILD instructions
|
|
HasOnBuild bool
|
|
|
|
// BuildVolumes specifies a list of volumes to mount to container running the
|
|
// build.
|
|
BuildVolumes []string
|
|
|
|
// Labels specify labels and their values to be applied to the resulting image. Label keys
|
|
// must have non-zero length. The labels defined here override generated labels in case
|
|
// they have the same name.
|
|
Labels map[string]string
|
|
|
|
// SourceInfo provides the info about the source to be built rather than relying
|
|
// on the Downloader to retrieve it.
|
|
SourceInfo *SourceInfo
|
|
}
|
|
|
|
// EnvironmentSpec specifies a single environment variable.
|
|
type EnvironmentSpec struct {
|
|
Name string
|
|
Value string
|
|
}
|
|
|
|
// EnvironmentList contains list of environment variables.
|
|
type EnvironmentList []EnvironmentSpec
|
|
|
|
// ProxyConfig holds proxy configuration.
|
|
type ProxyConfig struct {
|
|
HTTPProxy *url.URL
|
|
HTTPSProxy *url.URL
|
|
}
|
|
|
|
// CGroupLimits holds limits used to constrain container resources.
|
|
type CGroupLimits struct {
|
|
MemoryLimitBytes int64
|
|
CPUShares int64
|
|
CPUPeriod int64
|
|
CPUQuota int64
|
|
MemorySwap int64
|
|
}
|
|
|
|
// VolumeSpec represents a single volume mount point.
|
|
type VolumeSpec struct {
|
|
Source string
|
|
Destination string
|
|
}
|
|
|
|
// VolumeList contains list of VolumeSpec.
|
|
type VolumeList []VolumeSpec
|
|
|
|
// DockerConfig contains the configuration for a Docker connection.
|
|
type DockerConfig struct {
|
|
// Endpoint is the docker network endpoint or socket
|
|
Endpoint string
|
|
|
|
// CertFile is the certificate file path for a TLS connection
|
|
CertFile string
|
|
|
|
// KeyFile is the key file path for a TLS connection
|
|
KeyFile string
|
|
|
|
// CAFile is the certificate authority file path for a TLS connection
|
|
CAFile string
|
|
|
|
// UseTLS indicates if TLS must be used
|
|
UseTLS bool
|
|
|
|
// TLSVerify indicates if TLS peer must be verified
|
|
TLSVerify bool
|
|
}
|
|
|
|
// AuthConfig is our abstraction of the Registry authorization information for whatever
|
|
// docker client we happen to be based on
|
|
type AuthConfig struct {
|
|
Username string
|
|
Password string
|
|
Email string
|
|
ServerAddress string
|
|
}
|
|
|
|
// ContainerConfig is the abstraction of the docker client provider (formerly go-dockerclient, now either
|
|
// engine-api or kube docker client) container.Config type that is leveraged by s2i or origin
|
|
type ContainerConfig struct {
|
|
Labels map[string]string
|
|
Env []string
|
|
}
|
|
|
|
// Image is the abstraction of the docker client provider (formerly go-dockerclient, now either
|
|
// engine-api or kube docker client) Image type that is leveraged by s2i or origin
|
|
type Image struct {
|
|
ID string
|
|
*ContainerConfig
|
|
Config *ContainerConfig
|
|
}
|
|
|
|
// Result structure contains information from build process.
|
|
type Result struct {
|
|
|
|
// Success describes whether the build was successful.
|
|
Success bool
|
|
|
|
// Messages is a list of messages from build process.
|
|
Messages []string
|
|
|
|
// WorkingDir describes temporary directory used for downloading sources, scripts and tar operations.
|
|
WorkingDir string
|
|
|
|
// ImageID describes resulting image ID.
|
|
ImageID string
|
|
|
|
// BuildInfo holds information about the result of a build.
|
|
BuildInfo BuildInfo
|
|
}
|
|
|
|
// BuildInfo holds information about a particular step in the build process.
|
|
type BuildInfo struct {
|
|
// FailureReason is a camel case reason that is used by the machine to reply
|
|
// back to the OpenShift builder with information why any of the steps in the
|
|
// build, failed.
|
|
FailureReason FailureReason
|
|
}
|
|
|
|
// StepFailureReason holds the type of failure that occurred during the build
|
|
// process.
|
|
type StepFailureReason string
|
|
|
|
// StepFailureMessage holds the detailed message of a failure.
|
|
type StepFailureMessage string
|
|
|
|
// FailureReason holds the type of failure that occurred during the build
|
|
// process.
|
|
type FailureReason struct {
|
|
Reason StepFailureReason
|
|
Message StepFailureMessage
|
|
}
|
|
|
|
// InstallResult structure describes the result of install operation
|
|
type InstallResult struct {
|
|
|
|
// Script describes which script this result refers to
|
|
Script string
|
|
|
|
// URL describes from where the script was taken
|
|
URL string
|
|
|
|
// Downloaded describes if download operation happened, this will be true for
|
|
// external scripts, but false for scripts from inside the image
|
|
Downloaded bool
|
|
|
|
// Installed describes if script was installed to upload directory
|
|
Installed bool
|
|
|
|
// Error describes last error encountered during install operation
|
|
Error error
|
|
|
|
// FailedSources is a list of sources that were attempted but failed
|
|
// when downloading this script
|
|
FailedSources []string
|
|
}
|
|
|
|
// SourceInfo stores information about the source code
|
|
type SourceInfo struct {
|
|
// Ref represents a commit SHA-1, valid Git branch name or a Git tag
|
|
// The output image will contain this information as 'io.openshift.build.commit.ref' label.
|
|
Ref string
|
|
|
|
// CommitID represents an arbitrary extended object reference in Git as SHA-1
|
|
// The output image will contain this information as 'io.openshift.build.commit.id' label.
|
|
CommitID string
|
|
|
|
// Date contains a date when the committer created the commit.
|
|
// The output image will contain this information as 'io.openshift.build.commit.date' label.
|
|
Date string
|
|
|
|
// AuthorName contains the name of the author
|
|
// The output image will contain this information (along with AuthorEmail) as 'io.openshift.build.commit.author' label.
|
|
AuthorName string
|
|
|
|
// AuthorEmail contains the e-mail of the author
|
|
// The output image will contain this information (along with AuthorName) as 'io.openshift.build.commit.author' lablel.
|
|
AuthorEmail string
|
|
|
|
// CommitterName contains the name of the committer
|
|
CommitterName string
|
|
|
|
// CommitterEmail contains the e-mail of the committer
|
|
CommitterEmail string
|
|
|
|
// Message represents the first 80 characters from the commit message.
|
|
// The output image will contain this information as 'io.openshift.build.commit.message' label.
|
|
Message string
|
|
|
|
// Location contains a valid URL to the original repository.
|
|
// The output image will contain this information as 'io.openshift.build.source-location' label.
|
|
Location string
|
|
|
|
// ContextDir contains path inside the Location directory that
|
|
// contains the application source code.
|
|
// The output image will contain this information as 'io.openshift.build.source-context-dir'
|
|
// label.
|
|
ContextDir string
|
|
}
|
|
|
|
// CloneConfig specifies the options used when cloning the application source
|
|
// code.
|
|
type CloneConfig struct {
|
|
Recursive bool
|
|
Quiet bool
|
|
}
|
|
|
|
// DockerNetworkMode specifies the network mode setting for the docker container
|
|
type DockerNetworkMode string
|
|
|
|
const (
|
|
// DockerNetworkModeHost places the container in the default (host) network namespace.
|
|
DockerNetworkModeHost DockerNetworkMode = "host"
|
|
// DockerNetworkModeBridge instructs docker to create a network namespace for this container connected to the docker0 bridge via a veth-pair.
|
|
DockerNetworkModeBridge DockerNetworkMode = "bridge"
|
|
// DockerNetworkModeContainerPrefix is the string prefix used by NewDockerNetworkModeContainer.
|
|
DockerNetworkModeContainerPrefix string = "container:"
|
|
)
|
|
|
|
// NewDockerNetworkModeContainer creates a DockerNetworkMode value which instructs docker to place the container in the network namespace of an existing container.
|
|
// It can be used, for instance, to place the s2i container in the network namespace of the infrastructure container of a k8s pod.
|
|
func NewDockerNetworkModeContainer(id string) DockerNetworkMode {
|
|
return DockerNetworkMode(DockerNetworkModeContainerPrefix + id)
|
|
}
|
|
|
|
// PullPolicy specifies a type for the method used to retrieve the Docker image
|
|
type PullPolicy string
|
|
|
|
// String implements the String() function of pflags.Value so this can be used as
|
|
// command line parameter.
|
|
// This method is really used just to show the default value when printing help.
|
|
// It will not default the configuration.
|
|
func (p *PullPolicy) String() string {
|
|
if len(string(*p)) == 0 {
|
|
return string(DefaultBuilderPullPolicy)
|
|
}
|
|
return string(*p)
|
|
}
|
|
|
|
// Type implements the Type() function of pflags.Value interface
|
|
func (p *PullPolicy) Type() string {
|
|
return "string"
|
|
}
|
|
|
|
// Set implements the Set() function of pflags.Value interface
|
|
// The valid options are "always", "never" or "if-not-present"
|
|
func (p *PullPolicy) Set(v string) error {
|
|
switch v {
|
|
case "always":
|
|
*p = PullAlways
|
|
case "never":
|
|
*p = PullNever
|
|
case "if-not-present":
|
|
*p = PullIfNotPresent
|
|
default:
|
|
return fmt.Errorf("invalid value %q, valid values are: always, never or if-not-present", v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsInvalidFilename verifies if the provided filename contains malicious
|
|
// characters.
|
|
func IsInvalidFilename(name string) bool {
|
|
return strings.ContainsAny(name, invalidFilenameCharacters)
|
|
}
|
|
|
|
// Set implements the Set() function of pflags.Value interface.
|
|
// This function parses the string that contains source:destination pair.
|
|
// When the destination is not specified, the source get copied into current
|
|
// working directory in container.
|
|
func (l *VolumeList) Set(value string) error {
|
|
if len(value) == 0 {
|
|
return errors.New("invalid format, must be source:destination")
|
|
}
|
|
var mount []string
|
|
pos := strings.LastIndex(value, ":")
|
|
if pos == -1 {
|
|
mount = []string{value, ""}
|
|
} else {
|
|
mount = []string{value[:pos], value[pos+1:]}
|
|
}
|
|
mount[0] = strings.Trim(mount[0], `"'`)
|
|
mount[1] = strings.Trim(mount[1], `"'`)
|
|
s := VolumeSpec{Source: filepath.Clean(mount[0]), Destination: filepath.ToSlash(filepath.Clean(mount[1]))}
|
|
if IsInvalidFilename(s.Source) || IsInvalidFilename(s.Destination) {
|
|
return fmt.Errorf("invalid characters in filename: %q", value)
|
|
}
|
|
*l = append(*l, s)
|
|
return nil
|
|
}
|
|
|
|
// String implements the String() function of pflags.Value interface.
|
|
func (l *VolumeList) String() string {
|
|
result := []string{}
|
|
for _, i := range *l {
|
|
result = append(result, strings.Join([]string{i.Source, i.Destination}, ":"))
|
|
}
|
|
return strings.Join(result, ",")
|
|
}
|
|
|
|
// Type implements the Type() function of pflags.Value interface.
|
|
func (l *VolumeList) Type() string {
|
|
return "string"
|
|
}
|
|
|
|
// Set implements the Set() function of pflags.Value interface.
|
|
func (e *EnvironmentList) Set(value string) error {
|
|
parts := strings.SplitN(value, "=", 2)
|
|
if len(parts) != 2 || len(parts[0]) == 0 {
|
|
return fmt.Errorf("invalid environment format %q, must be NAME=VALUE", value)
|
|
}
|
|
if strings.Contains(parts[1], ",") && strings.Contains(parts[1], "=") {
|
|
glog.Warningf("DEPRECATED: Use multiple -e flags to specify multiple environment variables instead of comma (%q)", value)
|
|
}
|
|
*e = append(*e, EnvironmentSpec{
|
|
Name: strings.TrimSpace(parts[0]),
|
|
Value: strings.TrimSpace(parts[1]),
|
|
})
|
|
return nil
|
|
}
|
|
|
|
// String implements the String() function of pflags.Value interface.
|
|
func (e *EnvironmentList) String() string {
|
|
result := []string{}
|
|
for _, i := range *e {
|
|
result = append(result, strings.Join([]string{i.Name, i.Value}, "="))
|
|
}
|
|
return strings.Join(result, ",")
|
|
}
|
|
|
|
// Type implements the Type() function of pflags.Value interface.
|
|
func (e *EnvironmentList) Type() string {
|
|
return "string"
|
|
}
|
|
|
|
// AsBinds converts the list of volume definitions to go-dockerclient compatible
|
|
// list of bind mounts.
|
|
func (l *VolumeList) AsBinds() []string {
|
|
result := make([]string, len(*l))
|
|
for index, v := range *l {
|
|
result[index] = strings.Join([]string{v.Source, v.Destination}, ":")
|
|
}
|
|
return result
|
|
}
|