1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00
sap-jenkins-library/cmd/awsS3Upload.go
Julian Schmitt 6714794066
Create awsS3Upload (#3737)
* add Step awsS3Upload

* fix JSON Read

* fix groovy wrapper

* change credentials to secret text

* Change credentials type to token

* add cleanup for environment variables

* Add AwsS3UploadCommand to piper.go

* add documentation of awsS3Upload

* Fix JSON String Example in Documentation

* add the Upload of whole directories

* add Logging to awsS3Upload.go

* imporve Logging

* fix and improve unit tests

* fix non-existing-filepaths-Bug

* fix windows filepaths

* remove ... from logging

* change step description

* fix PR Tests

* remove redundant code

* try to run tests sequentially

* fix file.Close

* executed go mod tidy

* requested changes

* fix comments and awsCredentials

* Update documentation/docs/steps/awsS3Upload.md

Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>

* use temporary files for unit tests

* executed go generate

Co-authored-by: ffeldmann <f.feldmann@sap.com>
Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>
Co-authored-by: Thorsten Duda <thorsten.duda@sap.com>
2022-05-18 10:37:54 +02:00

143 lines
4.4 KiB
Go

package cmd
import (
"context"
"encoding/json"
"os"
"path/filepath"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
// S3PutObjectAPI defines the interface for the PutObject function.
// We use this interface to test the function using a mocked service.
type S3PutObjectAPI interface {
PutObject(ctx context.Context,
params *s3.PutObjectInput,
optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error)
}
// PutFile uploads a file to an AWS S3 bucket
// The function needs a context (including the AWS Region) and a PutObjectInput for the service call
// The return value is a PutObjectOutput with the result of the upload
func PutFile(c context.Context, api S3PutObjectAPI, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) {
return api.PutObject(c, input)
}
// Struct to store the AWS credentials from a specified JSON string
type awsCredentials struct {
AwsAccessKeyID string `json:"access_key_id"`
Bucket string `json:"bucket"`
AwsSecretAccessKey string `json:"secret_access_key"`
AwsRegion string `json:"region"`
}
func awsS3Upload(configOptions awsS3UploadOptions, telemetryData *telemetry.CustomData) {
// Prepare Credentials
log.Entry().Infoln("Start reading AWS Credentials")
var obj awsCredentials
err := json.Unmarshal([]byte(configOptions.JSONCredentialsAWS), &obj)
if err != nil {
log.Entry().
WithError(err).
Fatal("Could not read JSONCredentialsAWS")
}
// Set environment variables which are needed to initialize S3 Client
log.Entry().Infoln("Successfully read AWS Credentials. Setting up environment variables")
awsRegionSet := setenvIfEmpty("AWS_REGION", obj.AwsRegion)
awsAccessKeyIDSet := setenvIfEmpty("AWS_ACCESS_KEY_ID", obj.AwsAccessKeyID)
awsSecretAccessKeySet := setenvIfEmpty("AWS_SECRET_ACCESS_KEY", obj.AwsSecretAccessKey)
defer removeEnvIfPreviouslySet("AWS_REGION", awsRegionSet)
defer removeEnvIfPreviouslySet("AWS_ACCESS_KEY_ID", awsAccessKeyIDSet)
defer removeEnvIfPreviouslySet("AWS_SECRET_ACCESS_KEY", awsSecretAccessKeySet)
// Initialize S3 Client
log.Entry().Infoln("Loading Configuration for S3 Client")
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Entry().
WithError(err).
Fatal("AWS Client Configuration failed")
}
client := s3.NewFromConfig(cfg)
err = runAwsS3Upload(&configOptions, client, obj.Bucket)
if err != nil {
log.Entry().WithError(err).Fatal("Step execution failed")
}
}
func runAwsS3Upload(configOptions *awsS3UploadOptions, client S3PutObjectAPI, bucket string) error {
// Iterate through directories
err := filepath.Walk(configOptions.FilePath, func(currentFilePath string, f os.FileInfo, err error) error {
// Handle Failure to prevent panic (e.g. in case of an invalid filepath)
if err != nil {
log.Entry().WithError(err).Warnf("Failed to access path: '%v'", currentFilePath)
return err
}
// Skip directories, only upload files
if !f.IsDir() {
log.Entry().Infof("Current target path is: '%v'", currentFilePath)
// Open File
currentFile, e := os.Open(currentFilePath)
if e != nil {
log.Entry().WithError(e).Warnf("Could not open the file '%s'", currentFilePath)
return e
}
defer currentFile.Close()
// AWS SDK needs UNIX file paths to automatically create directories
key := filepath.ToSlash(currentFilePath)
// Intitialize S3 PutObjectInput
inputObject := &s3.PutObjectInput{
Bucket: &bucket,
Key: &key,
Body: currentFile,
}
// Upload File
log.Entry().Infof("Start upload of file '%v'", currentFilePath)
_, e = PutFile(context.TODO(), client, inputObject)
if e != nil {
log.Entry().WithError(e).Warnf("There was an error during the upload of file '%v'", currentFilePath)
return e
}
log.Entry().Infof("Upload of file '%v' was successful!", currentFilePath)
return e
}
return nil
})
if err != nil {
return err
}
log.Entry().Infoln("Upload has successfully finished!")
return err
}
// Function to set environment variables if they are not already set
func setenvIfEmpty(env, val string) bool {
if len(os.Getenv(env)) == 0 {
os.Setenv(env, val)
return true
}
return false
}
// Function to remove environment variables if they are set
func removeEnvIfPreviouslySet(env string, previouslySet bool) {
if previouslySet {
os.Setenv(env, "")
}
}