mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
d395b362ed
* shell executor initial commit * functionality updates * changes in logging implementation (using internal logging), changes in execution * remove unused field * remove duplicate from code * update vault flow and remove unnecessary params * update generated step file Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
package cmd
|
|
|
|
import (
|
|
"net/url"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/vault/api"
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/SAP/jenkins-library/pkg/command"
|
|
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
|
"github.com/SAP/jenkins-library/pkg/vault"
|
|
)
|
|
|
|
type shellExecuteUtils interface {
|
|
command.ExecRunner
|
|
FileExists(filename string) (bool, error)
|
|
}
|
|
|
|
type shellExecuteUtilsBundle struct {
|
|
*vault.Client
|
|
*command.Command
|
|
*piperutils.Files
|
|
}
|
|
|
|
func newShellExecuteUtils() shellExecuteUtils {
|
|
utils := shellExecuteUtilsBundle{
|
|
Command: &command.Command{},
|
|
Files: &piperutils.Files{},
|
|
}
|
|
utils.Stdout(log.Writer())
|
|
utils.Stderr(log.Writer())
|
|
return &utils
|
|
}
|
|
|
|
func shellExecute(config shellExecuteOptions, telemetryData *telemetry.CustomData) {
|
|
utils := newShellExecuteUtils()
|
|
fileUtils := &piperutils.Files{}
|
|
|
|
err := runShellExecute(&config, telemetryData, utils, fileUtils)
|
|
if err != nil {
|
|
log.Entry().WithError(err).Fatal("step execution failed")
|
|
}
|
|
}
|
|
|
|
func runShellExecute(config *shellExecuteOptions, telemetryData *telemetry.CustomData, utils shellExecuteUtils, fileUtils piperutils.FileUtils) error {
|
|
// create vault client
|
|
// try to retrieve existing credentials
|
|
// if it's impossible - will add it
|
|
vaultConfig := &vault.Config{
|
|
Config: &api.Config{
|
|
Address: config.VaultServerURL,
|
|
},
|
|
Namespace: config.VaultNamespace,
|
|
}
|
|
_, err := vault.NewClientWithAppRole(vaultConfig, GeneralConfig.VaultRoleID, GeneralConfig.VaultRoleSecretID)
|
|
if err != nil {
|
|
log.Entry().Info("could not create vault client:", err)
|
|
}
|
|
|
|
// piper http client for downloading scripts
|
|
httpClient := piperhttp.Client{}
|
|
|
|
// scripts for running locally
|
|
var e []string
|
|
|
|
// check input data
|
|
// example for script: sources: ["./script.sh"]
|
|
for _, source := range config.Sources {
|
|
// check it's a local script or remote
|
|
_, err := url.ParseRequestURI(source)
|
|
if err != nil {
|
|
// err means that it's not a remote script
|
|
// check if the script is physically present (for local scripts)
|
|
exists, err := fileUtils.FileExists(source)
|
|
if err != nil {
|
|
log.Entry().WithError(err).Error("failed to check for defined script")
|
|
return errors.Wrap(err, "failed to check for defined script")
|
|
}
|
|
if !exists {
|
|
log.Entry().WithError(err).Error("the specified script could not be found")
|
|
return errors.New("the specified script could not be found")
|
|
}
|
|
e = append(e, source)
|
|
} else {
|
|
// this block means that it's a remote script
|
|
// so, need to download it before
|
|
// get script name at first
|
|
path := strings.Split(source, "/")
|
|
err = httpClient.DownloadFile(source, path[len(path)-1], nil, nil)
|
|
if err != nil {
|
|
log.Entry().WithError(err).Errorf("the specified script could not be downloaded")
|
|
}
|
|
// make script executable
|
|
exec.Command("/bin/sh", "chmod +x "+path[len(path)-1])
|
|
|
|
e = append(e, path[len(path)-1])
|
|
|
|
}
|
|
}
|
|
|
|
// if all ok - try to run them one by one
|
|
for _, script := range e {
|
|
log.Entry().Info("starting running script:", script)
|
|
err = utils.RunExecutable(script)
|
|
if err != nil {
|
|
log.Entry().Errorln("starting running script:", script)
|
|
}
|
|
|
|
// if it's an exit error, then check the exit code
|
|
// according to the requirements
|
|
// 0 - success
|
|
// 1 - fails the build (or > 2)
|
|
// 2 - build unstable - unsupported now
|
|
if ee, ok := err.(*exec.ExitError); ok {
|
|
switch ee.ExitCode() {
|
|
case 0:
|
|
// success
|
|
return nil
|
|
case 1:
|
|
return errors.Wrap(err, "an error occurred while executing the script")
|
|
default:
|
|
// exit code 2 or >2 - unstable
|
|
return errors.Wrap(err, "script execution unstable or something went wrong")
|
|
}
|
|
} else if err != nil {
|
|
return errors.Wrap(err, "script execution error occurred")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|