2014-10-10 11:00:59 -04:00
package errors
import (
"fmt"
2016-12-12 10:01:59 +08:00
"os"
2018-06-21 08:48:20 -04:00
"github.com/openshift/source-to-image/pkg/api/constants"
2019-07-15 14:38:46 -04:00
utillog "github.com/openshift/source-to-image/pkg/util/log"
2014-10-10 11:00:59 -04:00
)
2016-12-12 10:01:59 +08:00
// Common S2I errors
2014-10-10 11:00:59 -04:00
const (
2015-02-20 11:36:44 +01:00
InspectImageError int = 1 + iota
PullImageError
SaveArtifactsError
AssembleError
WorkdirError
BuildError
TarTimeoutError
DownloadError
ScriptsInsideImageError
InstallError
InstallErrorRequired
URLHandlerError
STIContainerError
2015-06-10 17:12:22 -04:00
SourcePathError
2016-05-20 15:52:05 +02:00
UserNotAllowedError
2016-07-22 13:18:22 -04:00
EmptyGitRepositoryError
2014-10-10 11:00:59 -04:00
)
2016-12-12 10:01:59 +08:00
// Error represents an error thrown during S2I execution
2014-12-04 16:19:46 +01:00
type Error struct {
Message string
Details error
ErrorCode int
Suggestion string
}
// ContainerError is an error returned when a container exits with a non-zero code.
// ExitCode contains the exit code from the container
type ContainerError struct {
2015-01-20 16:54:33 +01:00
Message string
Output string
ErrorCode int
Suggestion string
ExitCode int
2014-12-04 16:19:46 +01:00
}
2014-10-10 11:00:59 -04:00
// Error returns a string for a given error
2014-12-04 16:19:46 +01:00
func ( s Error ) Error ( ) string {
return s . Message
}
// Error returns a string for the given error
func ( s ContainerError ) Error ( ) string {
return s . Message
}
// NewInspectImageError returns a new error which indicates there was a problem
// inspecting the image
func NewInspectImageError ( name string , err error ) error {
return Error {
Message : fmt . Sprintf ( "unable to get metadata for %s" , name ) ,
Details : err ,
2015-02-20 11:36:44 +01:00
ErrorCode : InspectImageError ,
2014-12-04 16:19:46 +01:00
Suggestion : "check image name" ,
}
}
// NewPullImageError returns a new error which indicates there was a problem
// pulling the image
func NewPullImageError ( name string , err error ) error {
return Error {
Message : fmt . Sprintf ( "unable to get %s" , name ) ,
Details : err ,
2015-02-20 11:36:44 +01:00
ErrorCode : PullImageError ,
2018-06-13 12:23:36 -04:00
Suggestion : fmt . Sprintf ( "check image name, or if using a local image set the builder image pull policy to %q" , "never" ) ,
2014-10-10 11:00:59 -04:00
}
}
2014-12-04 16:19:46 +01:00
// NewSaveArtifactsError returns a new error which indicates there was a problem
// calling save-artifacts script
2015-01-20 16:54:33 +01:00
func NewSaveArtifactsError ( name , output string , err error ) error {
2014-12-04 16:19:46 +01:00
return Error {
2015-01-20 16:54:33 +01:00
Message : fmt . Sprintf ( "saving artifacts for %s failed:\n%s" , name , output ) ,
2014-12-04 16:19:46 +01:00
Details : err ,
2015-02-20 11:36:44 +01:00
ErrorCode : SaveArtifactsError ,
2014-12-04 16:19:46 +01:00
Suggestion : "check the save-artifacts script for errors" ,
}
}
2015-01-20 16:54:33 +01:00
// NewAssembleError returns a new error which indicates there was a problem
// running assemble script
func NewAssembleError ( name , output string , err error ) error {
return Error {
Message : fmt . Sprintf ( "assemble for %s failed:\n%s" , name , output ) ,
Details : err ,
2015-02-20 11:36:44 +01:00
ErrorCode : AssembleError ,
2015-01-20 16:54:33 +01:00
Suggestion : "check the assemble script output for errors" ,
}
}
2015-02-19 14:36:06 +01:00
// NewWorkDirError returns a new error which indicates there was a problem
// when creating working directory
func NewWorkDirError ( dir string , err error ) error {
return Error {
Message : fmt . Sprintf ( "creating temporary directory %s failed" , dir ) ,
Details : err ,
2015-02-20 11:36:44 +01:00
ErrorCode : WorkdirError ,
2015-02-19 14:36:06 +01:00
Suggestion : "check if you have access to your system's temporary directory" ,
}
}
2014-12-17 22:27:34 +01:00
// NewBuildError returns a new error which indicates there was a problem
2014-12-04 16:19:46 +01:00
// building the image
func NewBuildError ( name string , err error ) error {
return Error {
Message : fmt . Sprintf ( "building %s failed" , name ) ,
Details : err ,
2015-02-20 11:36:44 +01:00
ErrorCode : BuildError ,
2015-01-20 16:54:33 +01:00
Suggestion : "check the build output for errors" ,
2014-12-04 16:19:46 +01:00
}
}
2016-05-04 14:25:49 -04:00
// NewCommitError returns a new error which indicates there was a problem
// committing the image
func NewCommitError ( name string , err error ) error {
return Error {
Message : fmt . Sprintf ( "building %s failed when committing the image due to error: %v" , name , err ) ,
Details : err ,
ErrorCode : BuildError ,
Suggestion : "check the build output for errors" ,
}
}
2014-12-08 16:11:19 +01:00
// NewTarTimeoutError returns a new error which indicates there was a problem
// when sending or receiving tar stream
func NewTarTimeoutError ( ) error {
return Error {
Message : fmt . Sprintf ( "timeout waiting for tar stream" ) ,
Details : nil ,
2015-02-20 11:36:44 +01:00
ErrorCode : TarTimeoutError ,
2015-05-25 14:53:13 +02:00
Suggestion : "check the Source-To-Image scripts if it accepts tar stream for assemble and sends for save-artifacts" ,
2014-12-08 16:11:19 +01:00
}
}
// NewDownloadError returns a new error which indicates there was a problem
// when downloading a file
func NewDownloadError ( url string , code int ) error {
return Error {
Message : fmt . Sprintf ( "failed to retrieve %s, response code %d" , url , code ) ,
Details : nil ,
2015-02-20 11:36:44 +01:00
ErrorCode : DownloadError ,
2014-12-08 16:11:19 +01:00
Suggestion : "check the availability of the address" ,
}
}
2015-02-19 14:18:50 +01:00
// NewScriptsInsideImageError returns a new error which informs of scripts
// being placed inside the image
func NewScriptsInsideImageError ( url string ) error {
return Error {
Message : fmt . Sprintf ( "scripts inside the image: %s" , url ) ,
Details : nil ,
2015-02-20 11:36:44 +01:00
ErrorCode : ScriptsInsideImageError ,
2015-02-19 14:18:50 +01:00
Suggestion : "" ,
}
}
2015-02-19 14:36:06 +01:00
// NewInstallError returns a new error which indicates there was a problem
// when downloading a script
2015-02-20 13:50:46 +01:00
func NewInstallError ( script string ) error {
2015-02-19 14:36:06 +01:00
return Error {
Message : fmt . Sprintf ( "failed to install %v" , script ) ,
Details : nil ,
2015-02-20 11:36:44 +01:00
ErrorCode : InstallError ,
2018-06-13 12:23:36 -04:00
Suggestion : fmt . Sprintf ( "set the scripts URL parameter with the location of the S2I scripts, or check if the image has the %q label set" , constants . ScriptsURLLabel ) ,
2015-02-19 14:36:06 +01:00
}
}
// NewInstallRequiredError returns a new error which indicates there was a problem
// when downloading a required script
2015-06-26 11:56:21 +02:00
func NewInstallRequiredError ( scripts [ ] string , label string ) error {
2015-02-19 14:36:06 +01:00
return Error {
Message : fmt . Sprintf ( "failed to install %v" , scripts ) ,
Details : nil ,
2015-02-20 11:36:44 +01:00
ErrorCode : InstallErrorRequired ,
2018-06-13 12:23:36 -04:00
Suggestion : fmt . Sprintf ( "set the scripts URL parameter with the location of the S2I scripts, or check if the image has the %q label set" , constants . ScriptsURLLabel ) ,
2015-02-19 14:36:06 +01:00
}
}
2014-12-08 16:11:19 +01:00
// NewURLHandlerError returns a new error which indicates there was a problem
// when trying to read scripts URL
func NewURLHandlerError ( url string ) error {
return Error {
Message : fmt . Sprintf ( "no URL handler for %s" , url ) ,
Details : nil ,
2015-02-20 11:36:44 +01:00
ErrorCode : URLHandlerError ,
2014-12-08 16:11:19 +01:00
Suggestion : "check the URL" ,
}
}
2014-12-04 16:19:46 +01:00
// NewContainerError return a new error which indicates there was a problem
// invoking command inside container
2015-01-20 16:54:33 +01:00
func NewContainerError ( name string , code int , output string ) error {
2014-12-04 16:19:46 +01:00
return ContainerError {
2015-01-20 16:54:33 +01:00
Message : fmt . Sprintf ( "non-zero (%d) exit code from %s" , code , name ) ,
Output : output ,
2015-02-20 11:36:44 +01:00
ErrorCode : STIContainerError ,
2015-01-20 16:54:33 +01:00
Suggestion : "check the container logs for more information on the failure" ,
ExitCode : code ,
2014-12-04 16:19:46 +01:00
}
2014-10-10 11:00:59 -04:00
}
2015-06-10 17:12:22 -04:00
// NewSourcePathError returns a new error which indicates there was a problem
// when accessing the source code from the local filesystem
func NewSourcePathError ( path string ) error {
return Error {
Message : fmt . Sprintf ( "Local filesystem source path does not exist: %s" , path ) ,
Details : nil ,
ErrorCode : SourcePathError ,
Suggestion : "check the source code path on the local filesystem" ,
}
}
2015-08-03 11:34:26 -04:00
2016-05-20 15:52:05 +02:00
// NewUserNotAllowedError returns a new error that indicates that the build
// could not run because the image uses a user outside of the range of allowed users
func NewUserNotAllowedError ( image string , onbuild bool ) error {
2015-08-03 11:34:26 -04:00
var msg string
if onbuild {
msg = fmt . Sprintf ( "image %q includes at least one ONBUILD instruction that sets the user to a user that is not allowed" , image )
} else {
msg = fmt . Sprintf ( "image %q must specify a user that is numeric and within the range of allowed users" , image )
}
return Error {
Message : msg ,
2016-05-20 15:52:05 +02:00
ErrorCode : UserNotAllowedError ,
2018-06-13 12:23:36 -04:00
Suggestion : fmt . Sprintf ( "modify image %q to use a numeric user within the allowed range, or build without the allowed UIDs paremeter set" , image ) ,
2018-05-23 08:28:00 -04:00
}
}
// NewAssembleUserNotAllowedError returns a new error that indicates that the build
// could not run because the build or image uses an assemble user outside of the range
// of allowed users.
func NewAssembleUserNotAllowedError ( image string , usesConfig bool ) error {
var msg , suggestion string
if usesConfig {
msg = "assemble user must be numeric and within the range of allowed users"
2018-06-13 12:23:36 -04:00
suggestion = "build without the allowed UIDs or assemble user configurations set"
2018-05-23 08:28:00 -04:00
} else {
2018-06-21 08:48:20 -04:00
msg = fmt . Sprintf ( "image %q includes the %q label whose value is not within the allowed range" , image , constants . AssembleUserLabel )
2018-06-13 12:23:36 -04:00
suggestion = fmt . Sprintf ( "modify the %q label in image %q to use a numeric user within the allowed range, or build without the allowed UIDs configuration set" , constants . AssembleUserLabel , image )
2018-05-23 08:28:00 -04:00
}
return Error {
Message : msg ,
ErrorCode : UserNotAllowedError ,
Suggestion : suggestion ,
2015-08-03 11:34:26 -04:00
}
}
2016-07-22 13:18:22 -04:00
// NewEmptyGitRepositoryError returns a new error which indicates that a found
// .git directory has no tracking information, e.g. if the user simply used
// `git init` and forgot about the repository
func NewEmptyGitRepositoryError ( source string ) error {
return Error {
Message : fmt . Sprintf ( "The git repository \"%s\" has no tracking information or commits" , source ) ,
ErrorCode : EmptyGitRepositoryError ,
2018-06-13 12:23:36 -04:00
Suggestion : "Either commit files to the Git repository, remove the .git directory from the project, or force copy of source files to ignore the repository." ,
2016-07-22 13:18:22 -04:00
}
}
2016-12-12 10:01:59 +08:00
2019-07-15 14:38:46 -04:00
// log is a placeholder until the builders pass an output stream down
// client facing libraries should not be using log
var log = utillog . StderrLog
2016-12-12 10:01:59 +08:00
// CheckError checks input error.
// 1. if the input error is nil, the function does nothing but return.
// 2. if the input error is a kind of Error which is thrown during S2I execution,
// the function handle it with Suggestion and Details.
// 3. if the input error is a kind of system Error which is unknown, the function exit with 1.
func CheckError ( err error ) {
if err == nil {
return
}
if e , ok := err . ( Error ) ; ok {
2019-07-15 14:38:46 -04:00
log . Errorf ( "An error occurred: %v" , e )
log . Errorf ( "Suggested solution: %v" , e . Suggestion )
2016-12-12 10:01:59 +08:00
if e . Details != nil {
2019-07-15 14:38:46 -04:00
log . V ( 1 ) . Infof ( "Details: %v" , e . Details )
2016-12-12 10:01:59 +08:00
}
2019-07-15 14:38:46 -04:00
log . Error ( "If the problem persists consult the docs at https://github.com/openshift/source-to-image/tree/master/docs. " +
2016-12-12 10:01:59 +08:00
"Eventually reach us on freenode #openshift or file an issue at https://github.com/openshift/source-to-image/issues " +
2018-06-13 12:23:36 -04:00
"providing us with a log from your build using log output level 3." )
2016-12-12 10:01:59 +08:00
os . Exit ( e . ErrorCode )
} else {
2019-07-15 14:38:46 -04:00
log . Errorf ( "An error occurred: %v" , err )
2016-12-12 10:01:59 +08:00
os . Exit ( 1 )
}
}
2016-12-21 18:09:11 +08:00
// UsageError checks command usage error.
func UsageError ( msg string ) error {
return fmt . Errorf ( "%s" , msg )
}