mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-18 05:18:24 +02:00
586044192c
* kanikoExecute: improve user experience * ensure proper tags * update permissions in case a container runs with a different user we need to make sure that the orchestrator user can work on the file * update permissions * ensure availablility of directories on Jenkins * (fix) clean up tmp dir in test * add resilience for incorrect step yaml * incorporate PR feedback * Adds piper step to update deployment configuration in external git repository. https://github.wdf.sap.corp/ContinuousDelivery/piper-ita/issues/21 * Adds handling of branchName as an optional parameter * Update resources/metadata/gitopsUpdateDeployment.yaml Feedback about description Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com> * Adapt to interface guide * Refactors to GitopsExecRunner * Refactors to GitopsExecRunner in test * Removes unnecessary mocked methods * Adds tests for git utils * Adds new step to CommonStepsTest.groovy * Updates description from yaml * Restricts visibility of methods and interfaces Adds comments where necessary * Updates comments * Fixes URL name * updates description * updates generated file * Fixes compile issue in CommonStepsTest.groovy * Updates long description * Updates test to run green on all kind of OS * Removes global variables from tests * Default branch: master Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> * Typo in Hierarchy Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> * Refactors test to allow parallel execution * Renames utility variable in gitopsUpdateDeployment.go * Renames error variables in gitopsUpdateDeployment.go * simplified parameters for kubectl * Refactors util classes to use parameters rather than global variables * makes username and password mandatory * remove unnecessary mandatory flag * remove new methods from mock that are not necessary * replaces with EqualError * replaces with NoError * update generated file * refactor tests * refactor tests * make tests parallel executable * parallel execution of tests * Refactors interfaces to stop exposing interfaces * Feedback from PR * Simplifies failing mocks * Renames variables and interfaces * Fixes error messages * shorten variable names * Renames unused parameters in tests * Cleanup nil parameters * Typo * Wrap errors and remove unnecessary logs * Remove containername and filePath from GENERAL scope * correct generated file * corrects expected error messages Co-authored-by: OliverNocon <oliver.nocon@sap.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
176 lines
5.7 KiB
Go
176 lines
5.7 KiB
Go
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"github.com/SAP/jenkins-library/pkg/command"
|
|
"github.com/SAP/jenkins-library/pkg/docker"
|
|
gitUtil "github.com/SAP/jenkins-library/pkg/git"
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
"github.com/pkg/errors"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
type iGitopsUpdateDeploymentGitUtils interface {
|
|
CommitSingleFile(filePath, commitMessage string) (plumbing.Hash, error)
|
|
PushChangesToRepository(username, password string) error
|
|
PlainClone(username, password, serverURL, directory string) error
|
|
ChangeBranch(branchName string) error
|
|
}
|
|
|
|
type gitopsUpdateDeploymentFileUtils interface {
|
|
TempDir(dir, pattern string) (name string, err error)
|
|
RemoveAll(path string) error
|
|
FileWrite(path string, content []byte, perm os.FileMode) error
|
|
}
|
|
|
|
type gitopsUpdateDeploymentExecRunner interface {
|
|
RunExecutable(executable string, params ...string) error
|
|
Stdout(out io.Writer)
|
|
Stderr(err io.Writer)
|
|
}
|
|
|
|
type gitopsUpdateDeploymentGitUtils struct {
|
|
worktree *git.Worktree
|
|
repository *git.Repository
|
|
}
|
|
|
|
func (g *gitopsUpdateDeploymentGitUtils) CommitSingleFile(filePath, commitMessage string) (plumbing.Hash, error) {
|
|
return gitUtil.CommitSingleFile(filePath, commitMessage, g.worktree)
|
|
}
|
|
|
|
func (g *gitopsUpdateDeploymentGitUtils) PushChangesToRepository(username, password string) error {
|
|
return gitUtil.PushChangesToRepository(username, password, g.repository)
|
|
}
|
|
|
|
func (g *gitopsUpdateDeploymentGitUtils) PlainClone(username, password, serverURL, directory string) error {
|
|
var err error
|
|
g.repository, err = gitUtil.PlainClone(username, password, serverURL, directory)
|
|
if err != nil {
|
|
return errors.Wrap(err, "plain clone failed")
|
|
}
|
|
g.worktree, err = g.repository.Worktree()
|
|
return errors.Wrap(err, "failed to retrieve worktree")
|
|
}
|
|
|
|
func (g *gitopsUpdateDeploymentGitUtils) ChangeBranch(branchName string) error {
|
|
return gitUtil.ChangeBranch(branchName, g.worktree)
|
|
}
|
|
|
|
func gitopsUpdateDeployment(config gitopsUpdateDeploymentOptions, telemetryData *telemetry.CustomData) {
|
|
// for command execution use Command
|
|
var c gitopsUpdateDeploymentExecRunner = &command.Command{}
|
|
// reroute command output to logging framework
|
|
c.Stdout(log.Writer())
|
|
c.Stderr(log.Writer())
|
|
|
|
// for http calls import piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
|
// and use a &piperhttp.Client{} in a custom system
|
|
// Example: step checkmarxExecuteScan.go
|
|
|
|
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
|
|
err := runGitopsUpdateDeployment(&config, c, &gitopsUpdateDeploymentGitUtils{}, piperutils.Files{})
|
|
if err != nil {
|
|
log.Entry().WithError(err).Fatal("step execution failed")
|
|
}
|
|
}
|
|
|
|
func runGitopsUpdateDeployment(config *gitopsUpdateDeploymentOptions, command gitopsUpdateDeploymentExecRunner, gitUtils iGitopsUpdateDeploymentGitUtils, fileUtils gitopsUpdateDeploymentFileUtils) error {
|
|
temporaryFolder, err := fileUtils.TempDir(".", "temp-")
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to create temporary directory")
|
|
}
|
|
|
|
defer fileUtils.RemoveAll(temporaryFolder)
|
|
|
|
err = gitUtils.PlainClone(config.Username, config.Password, config.ServerURL, temporaryFolder)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to plain clone repository")
|
|
}
|
|
|
|
err = gitUtils.ChangeBranch(config.BranchName)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to change branch")
|
|
}
|
|
|
|
registryImage, err := buildRegistryPlusImage(config)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to apply kubectl command")
|
|
}
|
|
patchString := "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"" + config.ContainerName + "\",\"image\":\"" + registryImage + "\"}]}}}}"
|
|
|
|
filePath := filepath.Join(temporaryFolder, config.FilePath)
|
|
|
|
kubectlOutputBytes, err := runKubeCtlCommand(command, patchString, filePath)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to apply kubectl command")
|
|
}
|
|
|
|
err = fileUtils.FileWrite(filePath, kubectlOutputBytes, 0755)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to write file")
|
|
}
|
|
|
|
commit, err := commitAndPushChanges(config, gitUtils)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to commit and push changes")
|
|
}
|
|
|
|
log.Entry().Infof("Changes committed with %s", commit.String())
|
|
|
|
return nil
|
|
}
|
|
|
|
func runKubeCtlCommand(command gitopsUpdateDeploymentExecRunner, patchString string, filePath string) ([]byte, error) {
|
|
var kubectlOutput = bytes.Buffer{}
|
|
command.Stdout(&kubectlOutput)
|
|
|
|
kubeParams := []string{
|
|
"patch",
|
|
"--local",
|
|
"--output=yaml",
|
|
"--patch=" + patchString,
|
|
"--filename=" + filePath,
|
|
}
|
|
err := command.RunExecutable("kubectl", kubeParams...)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to apply kubectl command")
|
|
}
|
|
return kubectlOutput.Bytes(), nil
|
|
}
|
|
|
|
func buildRegistryPlusImage(config *gitopsUpdateDeploymentOptions) (string, error) {
|
|
registryURL := config.ContainerRegistryURL
|
|
if registryURL == "" {
|
|
return config.ContainerImage, nil
|
|
}
|
|
|
|
url, err := docker.ContainerRegistryFromURL(registryURL)
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "registry URL could not be extracted")
|
|
}
|
|
if url != "" {
|
|
url = url + "/"
|
|
}
|
|
return url + config.ContainerImage, nil
|
|
}
|
|
|
|
func commitAndPushChanges(config *gitopsUpdateDeploymentOptions, gitUtils iGitopsUpdateDeploymentGitUtils) (plumbing.Hash, error) {
|
|
commit, err := gitUtils.CommitSingleFile(config.FilePath, config.CommitMessage)
|
|
if err != nil {
|
|
return [20]byte{}, errors.Wrap(err, "committing changes failed")
|
|
}
|
|
|
|
err = gitUtils.PushChangesToRepository(config.Username, config.Password)
|
|
if err != nil {
|
|
return [20]byte{}, errors.Wrap(err, "pushing changes failed")
|
|
}
|
|
|
|
return commit, nil
|
|
}
|