1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-11-24 08:32:32 +02:00

Add abapEnvironmentRunATCCheck step (#1454)

* Minor changes

* Changed groovy file

* Changed generated file

* Changed yaml with container config

* Changed groovy config

* minor changes

* minor changes

* Changed yaml with aliases

* minor changes

* minor changes

* minor changes

* minor changes

* minor changes

* minor changes

* minor changes

* minor changes

* minor changes

* minor changes

* Changed yaml aliases

* Adapted naming conventions

* Removed error code at the end

* Adapted configuration

* Minor changes

* Minor changes

* Minor changes

* Removed spaces

* Removed docker-related config from groovy file

* Minor changes

* Minor changes

* Removed container config

* Corrected testing function name

* Deleted unnecessary parts

* Changed service deletion message

* Changed service deletion message

* Logging out before throwing error service deletion step fails

* Minor changes

* Minor changes

* Minor changes

* Delete .DS_Store

* Delete .DS_Store

* Delete .DS_Store

* Delete .DS_Store

* Minor changes

* Minor changes

* Minor changes

* Added newline at end of file

* Added newline at end of file

* Changes for Pull request optimization

* added documentaion

* Adapted documentation

* Adapted documentation

* Adapted documentation

* Adapted documentation

* Adapted documentation

* Added CFDeleteServiceKeys

* Added ServiceKey deletion tests

* added cfServiceKeys flag explanation to documentation

* removed trailing spaces from documentation

* resolving conflicts

* Changed deletion message an variable naming

* Changed tests

* Changed tests

* Changed tests

* Changed tests

* Changed CloudFoundryDeleteServiceOptions to options

* Changed CloudFoundryDeleteServiceOptions to options

* Minor changes

* Minor changes

* Changed variable naming

* Changed error handling

* Changed error handling and logging

* Changed documentation

* Simplified code

* Fixed CodeClimate issues

* Changed from returning err to nil where no errur returned needed

* Add cloudFoundryCreateServiceKey Go Step

* Changed Groovy File

* Changed aliases

* Removed unneccessary parts

* Minor changes

* Minor changes

* Adapted documentation

* Adapted tests

* Adapted Groovy File

* Changed Groovy file

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Removed Groovy Tests for cfCreateServiceKey

* Minor changes

* Added ATC Check YAML

* Added ATC Check generated files

* Added test class

* Added abapEnvironmentRunATCCheck

* Minor changes

* Minor changes

* Changed groovy

* Minor changes

* Changed groovy

* Changed groovy

* Minor changes

* Adapted Groovy imports

* Adapted Groovy imports

* Adapted Groovy imports

* Adapted Groovy

* Getting ATC results

* Changed error message

* changed groovy

* removed trailing spaces

* Added login check

* Minor changes

* Added step to whitelistScriptReference

* Added ATC error message handling

* Added groovy file

* Added step to groovy tests

* corrected metadata file

* Debugging

* Debugging

* Added yaml config parameter for ATC run

* Adapted file location of ATC run config to jenkins specific location

* Implementing universal pipeline logic for finding yaml config regardless of pipeline

* Changed error handling for reading config yaml file

* Changed atcrunconfig alias

* minor changes

* Minor changes

* Minor changes

* Changed back to dynamic file reading

* Minor changes

* filepath changes

* Removing CF Login

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Minor changes

* Removed whitespaces

* Added CF functions unit tests

* Added invalid parameter handling

* Removed package and SC flag

* Minor changes

* Changed tests

* Changed tests

* Changed tests

* Minor changes

* Changed tests

* removed unnecessary logout

* Added documentation

* Changed docu

* Changed docu

* Changed docu

* Changed docu

* Changed docu

* Changed docu

* Changed docu

* Changed docu

* Changed docu

* Changed docu

* Removed trailing spaces

* Added newline at end of file

* code climate fixes

* code climate fixes

* code climate fixes

* Minor changes

* Minor changes

* Minor changes

* Changed tests

* Test changes

* Splitted Cloud Foundry functions into two classes

* Removed two steps from whtielistScriptReference

* removed atcrunConfig alias

* issue fixes

* Changed docu

* Changed docu

* Changed docu

* Removed trailing spaced from docu

* Changed docu

* Go generator run

* Issue fixes

* Remove unnecessary imports

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>

* Update whitelistScript

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>

* Adding piperutils for writing xml file

* Persisting ATC Results with piperutils

* Set failonMissingReports to true

* Refactoring for CodeClimate

* Changed result file name

* Changed credentials aliases

* changing secret name

* Removing trailing spaces

* Added secret name and alias to docu

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
This commit is contained in:
dominiklendle 2020-05-13 14:51:48 +02:00 committed by GitHub
parent 4105f81f71
commit ac732b3065
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1404 additions and 2 deletions

View File

@ -0,0 +1,360 @@
package cmd
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"path/filepath"
"strconv"
"time"
"github.com/SAP/jenkins-library/pkg/cloudfoundry"
"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/ghodss/yaml"
"github.com/pkg/errors"
)
func abapEnvironmentRunATCCheck(config abapEnvironmentRunATCCheckOptions, telemetryData *telemetry.CustomData) {
var c = command.Command{}
var err error
c.Stdout(log.Entry().Writer())
c.Stderr(log.Entry().Writer())
client := piperhttp.Client{}
cookieJar, _ := cookiejar.New(nil)
clientOptions := piperhttp.ClientOptions{
CookieJar: cookieJar,
}
client.SetOptions(clientOptions)
var details connectionDetailsHTTP
var abapEndpoint string
//If Host flag is empty read ABAP endpoint from Service Key instead. Otherwise take ABAP system endpoint from config instead
if err == nil {
details, err = checkHost(config, details)
}
var resp *http.Response
//Fetch Xcrsf-Token
if err == nil {
abapEndpoint = details.URL
credentialsOptions := piperhttp.ClientOptions{
Username: details.User,
Password: details.Password,
CookieJar: cookieJar,
}
client.SetOptions(credentialsOptions)
details.XCsrfToken, err = fetchXcsrfToken("GET", details, nil, &client)
}
if err == nil {
resp, err = triggerATCrun(config, details, &client, abapEndpoint)
}
if err == nil {
err = handleATCresults(resp, details, &client, abapEndpoint)
}
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
log.Entry().Info("ATC run completed succesfully. The respective run results are listed above.")
}
func handleATCresults(resp *http.Response, details connectionDetailsHTTP, client piperhttp.Sender, abapEndpoint string) error {
var err error
location := resp.Header.Get("Location")
details.URL = abapEndpoint + location
location, err = pollATCRun(details, nil, client)
if err == nil {
details.URL = abapEndpoint + location
resp, err = getResultATCRun("GET", details, nil, client)
}
//Parse response
var body []byte
if err == nil {
body, err = ioutil.ReadAll(resp.Body)
}
if err == nil {
defer resp.Body.Close()
err = parseATCResult(body)
}
if err != nil {
return fmt.Errorf("Handling ATC result failed: %w", err)
}
return nil
}
func triggerATCrun(config abapEnvironmentRunATCCheckOptions, details connectionDetailsHTTP, client piperhttp.Sender, abapEndpoint string) (*http.Response, error) {
var atcConfigyamlFile []byte
filelocation, err := filepath.Glob(config.AtcConfig)
//Parse YAML ATC run configuration as body for ATC run trigger
if err == nil {
filename, _ := filepath.Abs(filelocation[0])
atcConfigyamlFile, err = ioutil.ReadFile(filename)
}
var ATCConfig ATCconfig
if err == nil {
var result []byte
result, err = yaml.YAMLToJSON(atcConfigyamlFile)
json.Unmarshal(result, &ATCConfig)
}
var packageString string
var softwareComponentString string
if err == nil {
packageString, softwareComponentString, err = buildATCCheckBody(ATCConfig)
}
//Trigger ATC run
var resp *http.Response
var bodyString = `<?xml version="1.0" encoding="UTF-8"?><atc:runparameters xmlns:atc="http://www.sap.com/adt/atc" xmlns:obj="http://www.sap.com/adt/objectset"><obj:objectSet>` + softwareComponentString + packageString + `</obj:objectSet></atc:runparameters>`
var body = []byte(bodyString)
if err == nil {
details.URL = abapEndpoint + "/sap/bc/adt/api/atc/runs?clientWait=false"
resp, err = runATC("POST", details, body, client)
}
if err != nil {
return resp, fmt.Errorf("Triggering ATC result failed: %w", err)
}
return resp, nil
}
func buildATCCheckBody(ATCConfig ATCconfig) (string, string, error) {
if len(ATCConfig.Objects.Package) == 0 && len(ATCConfig.Objects.SoftwareComponent) == 0 {
return "", "", fmt.Errorf("Error while parsing ATC run config. Please provide the packages and/or the software components to be checked! %w", errors.New("No Package or Software Component specified. Please provide either one or both of them"))
}
var packageString string
var softwareComponentString string
//Build Package XML body
if len(ATCConfig.Objects.Package) != 0 {
packageString += "<obj:packages>"
for _, s := range ATCConfig.Objects.Package {
packageString += `<obj:package value="` + s.Name + `" includeSubpackages="` + strconv.FormatBool(s.IncludeSubpackages) + `"/>`
}
packageString += "</obj:packages>"
}
//Build SC XML body
if len(ATCConfig.Objects.SoftwareComponent) != 0 {
softwareComponentString += "<obj:softwarecomponents>"
for _, s := range ATCConfig.Objects.SoftwareComponent {
softwareComponentString += `<obj:softwarecomponent value="` + s.Name + `"/>`
}
softwareComponentString += "</obj:softwarecomponents>"
}
return packageString, softwareComponentString, nil
}
func parseATCResult(body []byte) error {
if len(body) == 0 {
return fmt.Errorf("Parsing ATC result failed: %w", errors.New("Body is empty, can't parse empty body"))
}
parsedXML := new(Result)
xml.Unmarshal([]byte(body), &parsedXML)
err := ioutil.WriteFile("ATCResults.xml", body, 0644)
if err == nil {
var reports []piperutils.Path
reports = append(reports, piperutils.Path{Target: "ATCResults.xml", Name: "ATC Results", Mandatory: true})
piperutils.PersistReportsAndLinks("abapEnvironmentRunATCCheck", "", reports, nil)
for _, s := range parsedXML.Files {
for _, t := range s.ATCErrors {
log.Entry().Error("Error in file " + s.Key + ": " + t.Key)
}
}
}
if err != nil {
return fmt.Errorf("Writing results to XML file failed: %w", err)
}
return nil
}
func runATC(requestType string, details connectionDetailsHTTP, body []byte, client piperhttp.Sender) (*http.Response, error) {
log.Entry().WithField("ABAP endpoint: ", details.URL).Info("Triggering ATC run")
header := make(map[string][]string)
header["X-Csrf-Token"] = []string{details.XCsrfToken}
header["Content-Type"] = []string{"application/vnd.sap.atc.run.parameters.v1+xml; charset=utf-8;"}
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
if err != nil {
return req, fmt.Errorf("Triggering ATC run failed: %w", err)
}
defer req.Body.Close()
return req, err
}
func fetchXcsrfToken(requestType string, details connectionDetailsHTTP, body []byte, client piperhttp.Sender) (string, error) {
log.Entry().WithField("ABAP Endpoint: ", details.URL).Info("Fetching Xcrsf-Token")
details.URL += "/sap/bc/adt/api/atc/runs/00000000000000000000000000000000"
details.XCsrfToken = "fetch"
header := make(map[string][]string)
header["X-Csrf-Token"] = []string{details.XCsrfToken}
header["Accept"] = []string{"application/vnd.sap.atc.run.v1+xml"}
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
if err != nil {
return "", fmt.Errorf("Fetching Xcsrf-Token failed: %w", err)
}
defer req.Body.Close()
token := req.Header.Get("X-Csrf-Token")
return token, err
}
func checkHost(config abapEnvironmentRunATCCheckOptions, details connectionDetailsHTTP) (connectionDetailsHTTP, error) {
var err error
if config.Host == "" {
cfconfig := cloudfoundry.ServiceKeyOptions{
CfAPIEndpoint: config.CfAPIEndpoint,
CfOrg: config.CfOrg,
CfSpace: config.CfSpace,
Username: config.Username,
Password: config.Password,
CfServiceInstance: config.CfServiceInstance,
CfServiceKey: config.CfServiceKeyName,
}
if cfconfig.CfServiceInstance == "" || cfconfig.CfOrg == "" || cfconfig.CfAPIEndpoint == "" || cfconfig.CfSpace == "" || cfconfig.CfServiceKey == "" {
return details, errors.New("Parameters missing. Please provide EITHER the Host of the ABAP server OR the Cloud Foundry ApiEndpoint, Organization, Space, Service Instance and a corresponding Service Key for the Communication Scenario SAP_COM_0510")
}
var abapServiceKey cloudfoundry.ServiceKey
abapServiceKey, err = cloudfoundry.ReadServiceKeyAbapEnvironment(cfconfig, true)
if err != nil {
return details, fmt.Errorf("Reading Service Key failed: %w", err)
}
details.User = abapServiceKey.Abap.Username
details.Password = abapServiceKey.Abap.Password
details.URL = abapServiceKey.URL
return details, err
}
details.User = config.Username
details.Password = config.Password
details.URL = config.Host
return details, err
}
func pollATCRun(details connectionDetailsHTTP, body []byte, client piperhttp.Sender) (string, error) {
log.Entry().WithField("ABAP endpoint", details.URL).Info("Polling ATC run status")
for {
resp, err := getHTTPResponseATCRun("GET", details, nil, client)
if err != nil {
return "", fmt.Errorf("Getting HTTP response failed: %w", err)
}
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("Reading response body failed: %w", err)
}
x := new(Run)
xml.Unmarshal(bodyText, &x)
log.Entry().WithField("StatusCode", resp.StatusCode).Info("Status: " + x.Status)
if x.Status == "Not Created" {
return "", err
}
if x.Status == "Completed" {
return x.Link[0].Key, err
}
if x.Status == "" {
return "", fmt.Errorf("Could not get any response from ATC poll: %w", errors.New("Status from ATC run is empty. Either it's not an ABAP system or ATC run hasn't started"))
}
time.Sleep(5 * time.Second)
}
}
func getHTTPResponseATCRun(requestType string, details connectionDetailsHTTP, body []byte, client piperhttp.Sender) (*http.Response, error) {
log.Entry().WithField("ABAP Endpoint: ", details.URL).Info("Polling ATC run status")
header := make(map[string][]string)
header["Accept"] = []string{"application/vnd.sap.atc.run.v1+xml"}
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
if err != nil {
return req, fmt.Errorf("Getting ATC run status failed: %w", err)
}
return req, err
}
func getResultATCRun(requestType string, details connectionDetailsHTTP, body []byte, client piperhttp.Sender) (*http.Response, error) {
log.Entry().WithField("ABAP Endpoint: ", details.URL).Info("Getting ATC results")
header := make(map[string][]string)
header["x-csrf-token"] = []string{details.XCsrfToken}
header["Accept"] = []string{"application/vnd.sap.atc.checkstyle.v1+xml"}
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
if err != nil {
return req, fmt.Errorf("Getting ATC run results failed: %w", err)
}
return req, err
}
//ATCconfig object for parsing yaml config of software components and packages
type ATCconfig struct {
Objects ATCObjects `json:"atcobjects"`
}
//ATCObjects in form of packages and software components to be checked
type ATCObjects struct {
Package []Package `json:"package"`
SoftwareComponent []SoftwareComponent `json:"softwarecomponent"`
}
//Package for ATC run to be checked
type Package struct {
Name string `json:"name"`
IncludeSubpackages bool `json:"includesubpackage"`
}
//SoftwareComponent for ATC run to be checked
type SoftwareComponent struct {
Name string `json:"name"`
}
//Run Object for parsing XML
type Run struct {
XMLName xml.Name `xml:"run"`
Status string `xml:"status,attr"`
Link []Link `xml:"link"`
}
//Link of XML object
type Link struct {
Key string `xml:"href,attr"`
Value string `xml:",chardata"`
}
//Result from ATC check for all files that were checked
type Result struct {
XMLName xml.Name `xml:"checkstyle"`
Files []File `xml:"file"`
}
//File that contains ATC check with error for checked file
type File struct {
Key string `xml:"name,attr"`
Value string `xml:",chardata"`
ATCErrors []ATCError `xml:"error"`
}
//ATCError with message
type ATCError struct {
Key string `xml:"message,attr"`
Value string `xml:",chardata"`
}

View File

@ -0,0 +1,183 @@
// Code generated by piper's step-generator. DO NOT EDIT.
package cmd
import (
"fmt"
"os"
"time"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/spf13/cobra"
)
type abapEnvironmentRunATCCheckOptions struct {
AtcConfig string `json:"atcConfig,omitempty"`
CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"`
CfOrg string `json:"cfOrg,omitempty"`
CfServiceInstance string `json:"cfServiceInstance,omitempty"`
CfServiceKeyName string `json:"cfServiceKeyName,omitempty"`
CfSpace string `json:"cfSpace,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Host string `json:"host,omitempty"`
}
// AbapEnvironmentRunATCCheckCommand Runs an ATC Check
func AbapEnvironmentRunATCCheckCommand() *cobra.Command {
const STEP_NAME = "abapEnvironmentRunATCCheck"
metadata := abapEnvironmentRunATCCheckMetadata()
var stepConfig abapEnvironmentRunATCCheckOptions
var startTime time.Time
var createAbapEnvironmentRunATCCheckCmd = &cobra.Command{
Use: STEP_NAME,
Short: "Runs an ATC Check",
Long: `Run ATC Check`,
PreRunE: func(cmd *cobra.Command, args []string) error {
startTime = time.Now()
log.SetStepName(STEP_NAME)
log.SetVerbose(GeneralConfig.Verbose)
path, _ := os.Getwd()
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
log.RegisterHook(fatalHook)
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
if err != nil {
return err
}
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
log.RegisterHook(&sentryHook)
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
telemetryData := telemetry.CustomData{}
telemetryData.ErrorCode = "1"
handler := func() {
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
telemetry.Send(&telemetryData)
}
log.DeferExitHandler(handler)
defer handler()
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
abapEnvironmentRunATCCheck(stepConfig, &telemetryData)
telemetryData.ErrorCode = "0"
},
}
addAbapEnvironmentRunATCCheckFlags(createAbapEnvironmentRunATCCheckCmd, &stepConfig)
return createAbapEnvironmentRunATCCheckCmd
}
func addAbapEnvironmentRunATCCheckFlags(cmd *cobra.Command, stepConfig *abapEnvironmentRunATCCheckOptions) {
cmd.Flags().StringVar(&stepConfig.AtcConfig, "atcConfig", os.Getenv("PIPER_atcConfig"), "Path to a YAML configuration file for Packages and/or Software Components to be checked during ATC run")
cmd.Flags().StringVar(&stepConfig.CfAPIEndpoint, "cfApiEndpoint", os.Getenv("PIPER_cfApiEndpoint"), "Cloud Foundry API endpoint")
cmd.Flags().StringVar(&stepConfig.CfOrg, "cfOrg", os.Getenv("PIPER_cfOrg"), "CF org")
cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Parameter of ServiceInstance Name to delete CloudFoundry Service")
cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Parameter of CloudFoundry Service Key to be created")
cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "CF Space")
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User or E-Mail for CF")
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "User Password for CF User")
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP Cloud Platform ABAP Environment system")
cmd.MarkFlagRequired("atcConfig")
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("password")
}
// retrieve step metadata
func abapEnvironmentRunATCCheckMetadata() config.StepData {
var theMetaData = config.StepData{
Metadata: config.StepMetadata{
Name: "abapEnvironmentRunATCCheck",
Aliases: []config.Alias{},
},
Spec: config.StepSpec{
Inputs: config.StepInputs{
Parameters: []config.StepParameters{
{
Name: "atcConfig",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "cfApiEndpoint",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "cloudFoundry/apiEndpoint"}},
},
{
Name: "cfOrg",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "cloudFoundry/org"}},
},
{
Name: "cfServiceInstance",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "cloudFoundry/serviceInstance"}},
},
{
Name: "cfServiceKeyName",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "cloudFoundry/serviceKeyName"}},
},
{
Name: "cfSpace",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "cloudFoundry/space"}},
},
{
Name: "username",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "password",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "host",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
},
},
},
},
}
return theMetaData
}

View File

@ -0,0 +1,16 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAbapEnvironmentRunATCCheckCommand(t *testing.T) {
testCmd := AbapEnvironmentRunATCCheckCommand()
// only high level testing performed - details are tested in step generation procudure
assert.Equal(t, "abapEnvironmentRunATCCheck", testCmd.Use, "command name incorrect")
}

View File

@ -0,0 +1,316 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestHostConfig(t *testing.T) {
t.Run("Check Host: ABAP Endpoint", func(t *testing.T) {
config := abapEnvironmentRunATCCheckOptions{
Username: "testUser",
Password: "testPassword",
Host: "https://api.endpoint.com",
}
var con connectionDetailsHTTP
con, error := checkHost(config, con)
if error == nil {
assert.Equal(t, "testUser", con.User)
assert.Equal(t, "testPassword", con.Password)
assert.Equal(t, "https://api.endpoint.com", con.URL)
assert.Equal(t, "", con.XCsrfToken)
}
})
t.Run("No host/ServiceKey configuration", func(t *testing.T) {
//Testing without CfOrg parameter
config := abapEnvironmentRunATCCheckOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfSpace: "testSpace",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
}
var con connectionDetailsHTTP
con, err := checkHost(config, con)
assert.EqualError(t, err, "Parameters missing. Please provide EITHER the Host of the ABAP server OR the Cloud Foundry ApiEndpoint, Organization, Space, Service Instance and a corresponding Service Key for the Communication Scenario SAP_COM_0510")
//Testing without ABAP Host
config = abapEnvironmentRunATCCheckOptions{
Username: "testUser",
Password: "testPassword",
}
con, err = checkHost(config, con)
assert.EqualError(t, err, "Parameters missing. Please provide EITHER the Host of the ABAP server OR the Cloud Foundry ApiEndpoint, Organization, Space, Service Instance and a corresponding Service Key for the Communication Scenario SAP_COM_0510")
})
t.Run("Check Host: CF Service Key", func(t *testing.T) {
config := abapEnvironmentRunATCCheckOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfSpace: "testSpace",
CfOrg: "Test",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
}
var con connectionDetailsHTTP
con, error := checkHost(config, con)
if error == nil {
assert.Equal(t, "", con.User)
assert.Equal(t, "", con.Password)
assert.Equal(t, "", con.URL)
assert.Equal(t, "", con.XCsrfToken)
}
})
}
func TestATCTrigger(t *testing.T) {
t.Run("Trigger ATC run test", func(t *testing.T) {
tokenExpected := "myToken"
client := &clientMock{
Body: `ATC trigger test`,
Token: tokenExpected,
}
con := connectionDetailsHTTP{
User: "Test",
Password: "Test",
URL: "https://api.endpoint.com/Entity/",
}
resp, error := runATC("GET", con, []byte(client.Body), client)
if error == nil {
assert.Equal(t, tokenExpected, resp.Header["X-Csrf-Token"][0])
assert.Equal(t, int64(0), resp.ContentLength)
assert.Equal(t, []string([]string(nil)), resp.Header["Location"])
}
})
}
func TestFetchXcsrfToken(t *testing.T) {
t.Run("FetchXcsrfToken Test", func(t *testing.T) {
tokenExpected := "myToken"
client := &clientMock{
Body: `Xcsrf Token test`,
Token: tokenExpected,
}
con := connectionDetailsHTTP{
User: "Test",
Password: "Test",
URL: "https://api.endpoint.com/Entity/",
}
token, error := fetchXcsrfToken("GET", con, []byte(client.Body), client)
if error == nil {
assert.Equal(t, tokenExpected, token)
}
})
t.Run("failure case: fetch token", func(t *testing.T) {
tokenExpected := ""
client := &clientMock{
Body: `Xcsrf Token test`,
Token: "",
}
con := connectionDetailsHTTP{
User: "Test",
Password: "Test",
URL: "https://api.endpoint.com/Entity/",
}
token, error := fetchXcsrfToken("GET", con, []byte(client.Body), client)
if error == nil {
assert.Equal(t, tokenExpected, token)
}
})
}
func TestPollATCRun(t *testing.T) {
t.Run("ATC run Poll Test", func(t *testing.T) {
tokenExpected := "myToken"
client := &clientMock{
Body: `ATC Poll test`,
Token: tokenExpected,
}
con := connectionDetailsHTTP{
User: "Test",
Password: "Test",
URL: "https://api.endpoint.com/Entity/",
}
resp, err := pollATCRun(con, []byte(client.Body), client)
if err != nil {
assert.Equal(t, "", resp)
assert.EqualError(t, err, "Could not get any response from ATC poll: Status from ATC run is empty. Either it's not an ABAP system or ATC run hasn't started")
}
})
}
func TestGetHTTPResponseATCRun(t *testing.T) {
t.Run("Get HTTP Response from ATC run Test", func(t *testing.T) {
client := &clientMock{
Body: `HTTP response test`,
}
con := connectionDetailsHTTP{
User: "Test",
Password: "Test",
URL: "https://api.endpoint.com/Entity/",
}
resp, err := getHTTPResponseATCRun("GET", con, []byte(client.Body), client)
defer resp.Body.Close()
if err == nil {
assert.Equal(t, int64(0), resp.ContentLength)
assert.Equal(t, []string([]string(nil)), resp.Header["X-Crsf-Token"])
}
})
}
func TestGetResultATCRun(t *testing.T) {
t.Run("Get HTTP Response from ATC run Test", func(t *testing.T) {
client := &clientMock{
BodyList: []string{
`ATC result body`,
},
}
con := connectionDetailsHTTP{
User: "Test",
Password: "Test",
URL: "https://api.endpoint.com/Entity/",
}
resp, err := getResultATCRun("GET", con, []byte(client.Body), client)
defer resp.Body.Close()
if err == nil {
assert.Equal(t, int64(0), resp.ContentLength)
assert.Equal(t, []string([]string(nil)), resp.Header["X-Crsf-Token"])
}
})
}
func TestParseATCResult(t *testing.T) {
t.Run("succes case: test parsing example XML result", func(t *testing.T) {
bodyString := `<?xml version="1.0" encoding="UTF-8"?>
<checkstyle>
<file name="testFile">
<error message="testMessage">
</error>
<error message="testMessage2">
</error>
</file>
<file name="testFile2">
<error message="testMessage3">
</error>
</file>
</checkstyle>`
body := []byte(bodyString)
err := parseATCResult(body)
assert.Equal(t, nil, err)
})
t.Run("failure case: parsing empty xml", func(t *testing.T) {
var bodyString string
body := []byte(bodyString)
err := parseATCResult(body)
assert.EqualError(t, err, "Parsing ATC result failed: Body is empty, can't parse empty body")
})
}
func TestBuildATCCheckBody(t *testing.T) {
t.Run("Test build body with no software component and package", func(t *testing.T) {
expectedpackagestring := ""
expectedsoftwarecomponentstring := ""
var err error
var config ATCconfig
var packageString, softwarecomponentString string
packageString, softwarecomponentString, err = buildATCCheckBody(config)
assert.Equal(t, expectedpackagestring, packageString)
assert.Equal(t, expectedsoftwarecomponentstring, softwarecomponentString)
assert.EqualError(t, err, "Error while parsing ATC run config. Please provide the packages and/or the software components to be checked! No Package or Software Component specified. Please provide either one or both of them")
})
t.Run("success case: Test build body with example yaml config", func(t *testing.T) {
expectedpackagestring := "<obj:packages><obj:package value=\"testPackage\" includeSubpackages=\"true\"/><obj:package value=\"testPackage2\" includeSubpackages=\"false\"/></obj:packages>"
expectedsoftwarecomponentstring := "<obj:softwarecomponents><obj:softwarecomponent value=\"testSoftwareComponent\"/><obj:softwarecomponent value=\"testSoftwareComponent2\"/></obj:softwarecomponents>"
var err error
var config ATCconfig
config = ATCconfig{
ATCObjects{
Package: []Package{
Package{Name: "testPackage", IncludeSubpackages: true},
Package{Name: "testPackage2", IncludeSubpackages: false},
},
SoftwareComponent: []SoftwareComponent{
SoftwareComponent{Name: "testSoftwareComponent"},
SoftwareComponent{Name: "testSoftwareComponent2"},
},
},
}
var packageString, softwarecomponentString string
packageString, softwarecomponentString, err = buildATCCheckBody(config)
assert.Equal(t, expectedpackagestring, packageString)
assert.Equal(t, expectedsoftwarecomponentstring, softwarecomponentString)
assert.Equal(t, nil, err)
})
t.Run("failure case: Test build body with example yaml config with only packages and no software components", func(t *testing.T) {
expectedpackagestring := `<obj:packages><obj:package value="testPackage" includeSubpackages="true"/><obj:package value="testPackage2" includeSubpackages="false"/></obj:packages>`
expectedsoftwarecomponentstring := ""
var err error
var config ATCconfig
config = ATCconfig{
ATCObjects{
Package: []Package{
Package{Name: "testPackage", IncludeSubpackages: true},
Package{Name: "testPackage2", IncludeSubpackages: false},
},
},
}
var packageString, softwarecomponentString string
packageString, softwarecomponentString, err = buildATCCheckBody(config)
assert.Equal(t, expectedpackagestring, packageString)
assert.Equal(t, expectedsoftwarecomponentstring, softwarecomponentString)
assert.Equal(t, nil, err)
})
t.Run("success case: Test build body with example yaml config with no packages and only software components", func(t *testing.T) {
expectedpackagestring := ""
expectedsoftwarecomponentstring := `<obj:softwarecomponents><obj:softwarecomponent value="testSoftwareComponent"/><obj:softwarecomponent value="testSoftwareComponent2"/></obj:softwarecomponents>`
var err error
var config ATCconfig
config = ATCconfig{
ATCObjects{
SoftwareComponent: []SoftwareComponent{
SoftwareComponent{Name: "testSoftwareComponent"},
SoftwareComponent{Name: "testSoftwareComponent2"},
},
},
}
var packageString, softwarecomponentString string
packageString, softwarecomponentString, err = buildATCCheckBody(config)
assert.Equal(t, expectedpackagestring, packageString)
assert.Equal(t, expectedsoftwarecomponentstring, softwarecomponentString)
assert.Equal(t, nil, err)
})
}

View File

@ -64,7 +64,6 @@ func runCloudFoundryCreateServiceKey(config *cloudFoundryCreateServiceKeyOptions
} else {
cfCreateServiceKeyScript = []string{"create-service-key", config.CfServiceInstance, config.CfServiceKeyName, "-c", config.CfServiceKeyConfig}
}
err := c.RunExecutable("cf", cfCreateServiceKeyScript...)
if err != nil {
return fmt.Errorf("Failed to Create Service Key: %w", err)

View File

@ -79,6 +79,7 @@ func Execute() {
rootCmd.AddCommand(MavenBuildCommand())
rootCmd.AddCommand(MavenExecuteStaticCodeChecksCommand())
rootCmd.AddCommand(NexusUploadCommand())
rootCmd.AddCommand(AbapEnvironmentRunATCCheckCommand())
rootCmd.AddCommand(NpmExecuteScriptsCommand())
rootCmd.AddCommand(GctsCreateRepositoryCommand())
rootCmd.AddCommand(MalwareExecuteScanCommand())

View File

@ -0,0 +1,106 @@
# ${docGenStepName}
## ${docGenDescription}
## Prerequisites
* This step is for triggering an ATC run on an ABAP system.
* You can either provide the ABAP endpoint config to directly trigger ann ATC run on the ABAP system or optionally provide the Cloud Foundry parameters with your credentials to read a Service Key of a SAP Cloud Platform ABAP Environment instance in Cloud Foundry that contains all the details to trigger an ATC run.
* Regardless if you chose an ABAP endpoint directly or reading a Cloud Foundry Service Key you have to provide the configuration of the packages and software components you want to be checked in an ATC run in a .yml or .yaml file. This file must be stored in the same folder as the Jenkinsfile defining the pipeline.
Examples will be listed below.
## ${docGenParameters}
## ${docGenConfiguration}
## ${docJenkinsPluginDependencies}
## Examples
* ### ATC run via Cloud Foundry Service Key example in Jenkinsfile
The following example triggers an ATC run via reading the Service Key of an ABAP instance in Cloud Foundry.
You can store the credentials in Jenkins and use the cfCredentialsId parameter to authenticate to Cloud Foundry.
The username and password to authenticate to ABAP system will then be read from the Cloud Foundry Service Key that is bound to the ABAP instance.
This can be done accordingly:
```groovy
abapEnvironmentRunATCCheck(
cfApiEndpoint : 'https://test.server.com',
cfOrg : 'cfOrg',
cfSpace: 'cfSpace',
cfServiceInstance: 'myServiceInstance',
cfSserviceKeyName: 'myServiceKey',
cfCredentialsId: 'cfCredentialsId',
atcConfig: 'atcconfig.yml',
script: this,
)
```
To trigger the ATC run an ATC config file `atcconfig.yml` will be needed. Check section 'ATC config file example' for more information.
* ### ATC run via direct ABAP endpoint configuration in Jenkinsfile
This example triggers an ATC run directly on the ABAP endpoint.
In order to trigger the ATC run you have to pass the username and password for authentication to the ABAP endpoint via parameters as well as the ABAP endpoint/host. You can store the credentials in Jenkins and use the abapCredentialsId parameter to authenticate to the ABAP endpoint/host.
This must be configured as following:
```groovy
abapEnvironmentRunATCCheck(
abapCredentialsId: 'abapCredentialsId',
host: 'https://myABAPendpoint.com',
atcConfig: 'atcconfig.yml',
script: this,
)
```
To trigger the ATC run an ATC config file `atcconfig.yml` will be needed. Check section 'ATC config file example' for more information.
* ### ATC config file example
The following section contains an example of an `atcconfig.yml` file.
This file must be stored in the same Git folder where the `Jenkinsfile` is stored to run the pipeline. This folder must be taken as a SCM in the Jenkins pipeline to run the pipeline.
You can specify a list of packages and/or software components to be checked. This must be in the same format as below example for a `atcconfig.yml` file.
For each package that has to be checked you can configure if you want the subpackages to be included in checks or not.
Please note that if you chose to provide both packages and software components to be checked with the `atcconfig.yml` file, the set of packages and the set of software components will be combinend by the API using a logical AND operation.
Therefore, we advise to specify either the Software Components or Packages.
See below example for an `atcconfig.yml` file with both packages and software components to be checked:
```yaml
atcobjects:
package:
- name: "TestPackage"
includesubpackage: false
- name: "TestPackage2"
includesubpackage: true
softwarecomponent:
- name: "TestComponent"
- name: "TestComponent2"
```
The following example of an `atcconfig.yml` file that only contains packages to be checked:
```yaml
atcobjects:
package:
- name: "TestPackage"
includesubpackage: false
- name: "TestPackage2"
includesubpackage: true
```
The following example of an `atcconfig.yml` file that only contains software components to be checked:
```yaml
atcobjects:
softwarecomponent:
- name: "TestComponent"
- name: "TestComponent2"
```

View File

@ -0,0 +1,110 @@
package cloudfoundry
import (
"bytes"
"errors"
"fmt"
"strings"
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/log"
)
var c = command.Command{}
//LoginCheck checks if user is logged in to Cloud Foundry.
//If user is not logged in 'cf api' command will return string that contains 'User is not logged in' only if user is not logged in.
//If the returned string doesn't contain the substring 'User is not logged in' we know he is logged in.
func LoginCheck(options LoginOptions) (bool, error) {
var err error
if options.CfAPIEndpoint == "" {
return false, errors.New("Cloud Foundry API endpoint parameter missing. Please provide the Cloud Foundry Endpoint")
}
//Check if logged in --> Cf api command responds with "not logged in" if positive
var cfCheckLoginScript = []string{"api", options.CfAPIEndpoint}
var cfLoginBytes bytes.Buffer
c.Stdout(&cfLoginBytes)
var result string
err = c.RunExecutable("cf", cfCheckLoginScript...)
if err != nil {
return false, fmt.Errorf("Failed to check if logged in: %w", err)
}
result = cfLoginBytes.String()
log.Entry().WithField("result: ", result).Info("Login check")
//Logged in
if strings.Contains(result, "Not logged in") == false {
log.Entry().Info("Login check indicates you are already logged in to Cloud Foundry")
return true, err
}
//Not logged in
log.Entry().Info("Login check indicates you are not yet logged in to Cloud Foundry")
return false, err
}
//Login logs user in to Cloud Foundry via cf cli.
//Checks if user is logged in first, if not perform 'cf login' command with appropriate parameters
func Login(options LoginOptions) error {
var err error
if options.CfAPIEndpoint == "" || options.CfOrg == "" || options.CfSpace == "" || options.Username == "" || options.Password == "" {
return fmt.Errorf("Failed to login to Cloud Foundry: %w", errors.New("Parameters missing. Please provide the Cloud Foundry Endpoint, Org, Space, Username and Password"))
}
var loggedIn bool
loggedIn, err = LoginCheck(options)
if loggedIn == true {
return err
}
if err == nil {
log.Entry().Info("Logging in to Cloud Foundry")
var cfLoginScript = []string{"login", "-a", options.CfAPIEndpoint, "-o", options.CfOrg, "-s", options.CfSpace, "-u", options.Username, "-p", options.Password}
log.Entry().WithField("cfAPI:", options.CfAPIEndpoint).WithField("cfOrg", options.CfOrg).WithField("space", options.CfSpace).Info("Logging into Cloud Foundry..")
err = c.RunExecutable("cf", cfLoginScript...)
}
if err != nil {
return fmt.Errorf("Failed to login to Cloud Foundry: %w", err)
}
log.Entry().Info("Logged in successfully to Cloud Foundry..")
return nil
}
//Logout logs User out of Cloud Foundry
//Logout can be perforned via 'cf logout' command regardless if user is logged in or not
func Logout() error {
var cfLogoutScript = "logout"
log.Entry().Info("Logging out of Cloud Foundry")
err := c.RunExecutable("cf", cfLogoutScript)
if err != nil {
return fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
}
log.Entry().Info("Logged out successfully")
return nil
}
//LoginOptions for logging in to CF
type LoginOptions struct {
CfAPIEndpoint string
CfOrg string
CfSpace string
Username string
Password string
}

View File

@ -0,0 +1,83 @@
package cloudfoundry
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCloudFoundryLoginCheck(t *testing.T) {
t.Run("CF Login check: missing parameter", func(t *testing.T) {
cfconfig := LoginOptions{}
loggedIn, err := LoginCheck(cfconfig)
assert.Equal(t, false, loggedIn)
assert.EqualError(t, err, "Cloud Foundry API endpoint parameter missing. Please provide the Cloud Foundry Endpoint")
})
t.Run("CF Login check: failure case", func(t *testing.T) {
cfconfig := LoginOptions{
CfAPIEndpoint: "https://api.endpoint.com",
}
loggedIn, err := LoginCheck(cfconfig)
assert.Equal(t, false, loggedIn)
assert.Error(t, err)
})
}
func TestCloudFoundryLogin(t *testing.T) {
t.Run("CF Login: missing parameter", func(t *testing.T) {
cfconfig := LoginOptions{}
err := Login(cfconfig)
assert.EqualError(t, err, "Failed to login to Cloud Foundry: Parameters missing. Please provide the Cloud Foundry Endpoint, Org, Space, Username and Password")
})
t.Run("CF Login: failure", func(t *testing.T) {
cfconfig := LoginOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfSpace: "testSpace",
CfOrg: "testOrg",
Username: "testUser",
Password: "testPassword",
}
err := Login(cfconfig)
assert.Error(t, err)
})
}
func TestCloudFoundryLogout(t *testing.T) {
t.Run("CF Logout", func(t *testing.T) {
err := Logout()
if err == nil {
assert.Equal(t, nil, err)
} else {
assert.Error(t, err)
}
})
}
func TestCloudFoundryReadServiceKeyAbapEnvironment(t *testing.T) {
t.Run("CF ReadServiceKeyAbapEnvironment", func(t *testing.T) {
cfconfig := ServiceKeyOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfSpace: "testSpace",
CfOrg: "testOrg",
CfServiceInstance: "testInstance",
CfServiceKey: "testKey",
Username: "testUser",
Password: "testPassword",
}
var abapKey ServiceKey
abapKey, err := ReadServiceKeyAbapEnvironment(cfconfig, true)
assert.Equal(t, "", abapKey.Abap.Password)
assert.Equal(t, "", abapKey.Abap.Username)
assert.Equal(t, "", abapKey.Abap.CommunicationArrangementID)
assert.Equal(t, "", abapKey.Abap.CommunicationScenarioID)
assert.Equal(t, "", abapKey.Abap.CommunicationSystemID)
assert.Equal(t, "", abapKey.Binding.Env)
assert.Equal(t, "", abapKey.Binding.Type)
assert.Equal(t, "", abapKey.Binding.ID)
assert.Equal(t, "", abapKey.Binding.Version)
assert.Equal(t, "", abapKey.Systemid)
assert.Equal(t, "", abapKey.URL)
assert.Error(t, err)
})
}

View File

@ -0,0 +1,110 @@
package cloudfoundry
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/SAP/jenkins-library/pkg/log"
)
//ReadServiceKeyAbapEnvironment from Cloud Foundry and returns it.
//Depending on user/developer requirements if he wants to perform further Cloud Foundry actions the cfLogoutOption parameters gives the option to logout after reading ABAP communication arrangement or not.
func ReadServiceKeyAbapEnvironment(options ServiceKeyOptions, cfLogoutOption bool) (ServiceKey, error) {
var abapServiceKey ServiceKey
var err error
//Logging into Cloud Foundry
config := LoginOptions{
CfAPIEndpoint: options.CfAPIEndpoint,
CfOrg: options.CfOrg,
CfSpace: options.CfSpace,
Username: options.Username,
Password: options.Password,
}
err = Login(config)
var serviceKeyBytes bytes.Buffer
c.Stdout(&serviceKeyBytes)
if err == nil {
//Reading Service Key
log.Entry().WithField("cfServiceInstance", options.CfServiceInstance).WithField("cfServiceKey", options.CfServiceKey).Info("Read service key for service instance")
cfReadServiceKeyScript := []string{"service-key", options.CfServiceInstance, options.CfServiceKey}
err = c.RunExecutable("cf", cfReadServiceKeyScript...)
}
if err == nil {
var serviceKeyJSON string
if len(serviceKeyBytes.String()) > 0 {
var lines []string = strings.Split(serviceKeyBytes.String(), "\n")
serviceKeyJSON = strings.Join(lines[2:], "")
}
json.Unmarshal([]byte(serviceKeyJSON), &abapServiceKey)
if abapServiceKey == (ServiceKey{}) {
return abapServiceKey, errors.New("Parsing the service key failed")
}
log.Entry().Info("Service Key read successfully")
}
if err != nil {
if cfLogoutOption == true {
var logoutErr error
logoutErr = Logout()
if logoutErr != nil {
return abapServiceKey, fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
}
}
return abapServiceKey, fmt.Errorf("Reading Service Key failed: %w", err)
}
//Logging out of CF
if cfLogoutOption == true {
var logoutErr error
logoutErr = Logout()
if logoutErr != nil {
return abapServiceKey, fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
}
}
return abapServiceKey, nil
}
//ServiceKeyOptions for reading CF Service Key
type ServiceKeyOptions struct {
CfAPIEndpoint string
CfOrg string
CfSpace string
CfServiceInstance string
CfServiceKey string
Username string
Password string
}
//ServiceKey struct to parse CF Service Key
type ServiceKey struct {
Abap AbapConnection `json:"abap"`
Binding AbapBinding `json:"binding"`
Systemid string `json:"systemid"`
URL string `json:"url"`
}
//AbapConnection contains information about the ABAP connection for the ABAP endpoint
type AbapConnection struct {
CommunicationArrangementID string `json:"communication_arrangement_id"`
CommunicationScenarioID string `json:"communication_scenario_id"`
CommunicationSystemID string `json:"communication_system_id"`
Password string `json:"password"`
Username string `json:"username"`
}
//AbapBinding contains information about service binding in Cloud Foundry
type AbapBinding struct {
Env string `json:"env"`
ID string `json:"id"`
Type string `json:"type"`
Version string `json:"version"`
}

View File

@ -0,0 +1,106 @@
metadata:
name: abapEnvironmentRunATCCheck
description: Runs an ATC Check
longDescription: |
Run ATC Check
spec:
inputs:
secrets:
- name: abapCredentialsId
aliases:
- name: cfCredentialsId
description: Jenkins credentials ID containing user and password to authenticate to the Cloud Platform ABAP Environment system or the Cloud Foundry API
type: jenkins
params:
- name: atcConfig
type: string
description: Path to a YAML configuration file for Packages and/or Software Components to be checked during ATC run
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: true
- name: cfApiEndpoint
type: string
description: Cloud Foundry API endpoint
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
mandatory: false
aliases:
- name: cloudFoundry/apiEndpoint
- name: cfOrg
type: string
description: CF org
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
mandatory: false
aliases:
- name: cloudFoundry/org
- name: cfServiceInstance
type: string
description: Parameter of ServiceInstance Name to delete CloudFoundry Service
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
mandatory: false
aliases:
- name: cloudFoundry/serviceInstance
- name: cfServiceKeyName
type: string
description: Parameter of CloudFoundry Service Key to be created
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
mandatory: false
aliases:
- name: cloudFoundry/serviceKeyName
- name: cfSpace
type: string
description: CF Space
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
mandatory: false
aliases:
- name: cloudFoundry/space
- name: username
type: string
description: User or E-Mail for CF
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: true
- name: password
type: string
description: User Password for CF User
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: true
- name: host
type: string
description: Specifies the host address of the SAP Cloud Platform ABAP Environment system
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
containers:
- name: cf
image: ppiper/cf-cli
dockerWorkspace: '/home/piper'
imagePullPolicy: Never

View File

@ -132,6 +132,7 @@ public class CommonStepsTest extends BasePiperTest{
'mavenExecuteStaticCodeChecks', //implementing new golang pattern without fields
'nexusUpload', //implementing new golang pattern without fields
'piperPipelineStageArtifactDeployment', //stage without step flags
'abapEnvironmentRunATCCheck', //implementing new golang pattern without fields
'sonarExecuteScan', //implementing new golang pattern without fields
'gctsCreateRepository', //implementing new golang pattern without fields
]

View File

@ -0,0 +1,11 @@
import groovy.transform.Field
@Field String STEP_NAME = getClass().getName()
@Field String METADATA_FILE = 'metadata/abapEnvironmentRunATCCheck.yaml'
void call(Map parameters = [:]) {
List credentials = [
[type: 'usernamePassword', id: 'abapCredentialsId', env: ['PIPER_username', 'PIPER_password']]
]
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials, true, false, true)
}

View File

@ -7,5 +7,5 @@ void call(Map parameters = [:]) {
List credentials = [
[type: 'usernamePassword', id: 'cfCredentialsId', env: ['PIPER_username', 'PIPER_password']]
]
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials)
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials, false, false, true)
}