1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

Retry capabilities for HTTP requests + enablement for Checkmarx step (#2346)

This commit is contained in:
Sven Merk 2020-11-11 13:35:53 +01:00 committed by GitHub
parent a70933bbd4
commit 3c7712f2ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 5 deletions

View File

@ -26,6 +26,8 @@ import (
func checkmarxExecuteScan(config checkmarxExecuteScanOptions, telemetryData *telemetry.CustomData, influx *checkmarxExecuteScanInflux) {
client := &piperHttp.Client{}
options := piperHttp.ClientOptions{MaxRetries: config.MaxRetries}
client.SetOptions(options)
sys, err := checkmarx.NewSystemInstance(client, config.ServerURL, config.Username, config.Password)
if err != nil {
log.Entry().WithError(err).Fatalf("Failed to create Checkmarx client talking to URL %v", config.ServerURL)

View File

@ -22,6 +22,7 @@ type checkmarxExecuteScanOptions struct {
FullScansScheduled bool `json:"fullScansScheduled,omitempty"`
GeneratePdfReport bool `json:"generatePdfReport,omitempty"`
Incremental bool `json:"incremental,omitempty"`
MaxRetries int `json:"maxRetries,omitempty"`
Password string `json:"password,omitempty"`
Preset string `json:"preset,omitempty"`
ProjectName string `json:"projectName,omitempty"`
@ -235,6 +236,7 @@ func addCheckmarxExecuteScanFlags(cmd *cobra.Command, stepConfig *checkmarxExecu
cmd.Flags().BoolVar(&stepConfig.FullScansScheduled, "fullScansScheduled", true, "Whether full scans are to be scheduled or not. Should be used in relation with `incremental` and `fullScanCycle`")
cmd.Flags().BoolVar(&stepConfig.GeneratePdfReport, "generatePdfReport", true, "Whether to generate a PDF report of the analysis results or not")
cmd.Flags().BoolVar(&stepConfig.Incremental, "incremental", true, "Whether incremental scans are to be applied which optimizes the scan time but might reduce detection capabilities. Therefore full scans are still required from time to time and should be scheduled via `fullScansScheduled` and `fullScanCycle`")
cmd.Flags().IntVar(&stepConfig.MaxRetries, "maxRetries", 3, "Maximum number of HTTP request retries upon intermittend connetion interrupts")
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "The password to authenticate")
cmd.Flags().StringVar(&stepConfig.Preset, "preset", os.Getenv("PIPER_preset"), "The preset to use for scanning, if not set explicitly the step will attempt to look up the project's setting based on the availability of `checkmarxCredentialsId`")
cmd.Flags().StringVar(&stepConfig.ProjectName, "projectName", os.Getenv("PIPER_projectName"), "The name of the Checkmarx project to scan into")
@ -316,6 +318,14 @@ func checkmarxExecuteScanMetadata() config.StepData {
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "maxRetries",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "int",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "password",
ResourceRef: []config.ResourceReference{

2
go.mod
View File

@ -32,7 +32,7 @@ require (
github.com/google/uuid v1.1.2
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/hashicorp/go-retryablehttp v0.6.7 // indirect
github.com/hashicorp/go-retryablehttp v0.6.7
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/vault/api v1.0.4
github.com/huandu/xstrings v1.3.2 // indirect

View File

@ -17,6 +17,7 @@ import (
"time"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/hashicorp/go-retryablehttp"
"github.com/motemen/go-nuts/roundtime"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -25,6 +26,7 @@ import (
// Client defines an http client object
type Client struct {
maxRequestDuration time.Duration
maxRetries int
transportTimeout time.Duration
transportSkipVerification bool
username string
@ -43,6 +45,7 @@ type ClientOptions struct {
// for the request will be enforced. This should only be used if the
// length of the request bodies is known.
MaxRequestDuration time.Duration
MaxRetries int
// TransportTimeout defaults to 3 minutes, if not specified. It is
// used for the transport layer and duration of handshakes and such.
TransportTimeout time.Duration
@ -196,6 +199,7 @@ func (c *Client) SetOptions(options ClientOptions) {
c.username = options.Username
c.password = options.Password
c.token = options.Token
c.maxRetries = options.MaxRetries
if options.Logger != nil {
c.logger = options.Logger
@ -224,14 +228,26 @@ func (c *Client) initialize() *http.Client {
doLogRequestBodyOnDebug: c.doLogRequestBodyOnDebug,
doLogResponseBodyOnDebug: c.doLogResponseBodyOnDebug,
}
var httpClient = &http.Client{
Timeout: c.maxRequestDuration,
Transport: transport,
Jar: c.cookieJar,
var httpClient *http.Client
if c.maxRetries > 0 {
retryClient := retryablehttp.NewClient()
retryClient.HTTPClient.Timeout = c.maxRequestDuration
retryClient.HTTPClient.Jar = c.cookieJar
retryClient.HTTPClient.Transport = transport
retryClient.RetryMax = c.maxRetries
httpClient = retryClient.StandardClient()
} else {
httpClient = &http.Client{}
httpClient.Timeout = c.maxRequestDuration
httpClient.Jar = c.cookieJar
httpClient.Transport = transport
}
if c.transportSkipVerification {
c.logger.Debugf("TLS verification disabled")
}
c.logger.Debugf("Transport timeout: %v, max request duration: %v", c.transportTimeout, c.maxRequestDuration)
return httpClient

View File

@ -303,6 +303,32 @@ func TestTransportSkipVerification(t *testing.T) {
}
}
func TestMaxRetries(t *testing.T) {
testCases := []struct {
client Client
countedCalls int
}{
{client: Client{maxRetries: 0}, countedCalls: 1},
{client: Client{maxRetries: 2}, countedCalls: 3},
{client: Client{maxRetries: 3}, countedCalls: 4},
}
for _, testCase := range testCases {
// init
count := 0
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
w.WriteHeader(500)
}))
defer svr.Close()
// test
_, err := testCase.client.SendRequest(http.MethodGet, svr.URL, &bytes.Buffer{}, nil, nil)
// assert
assert.Error(t, err)
assert.Equal(t, testCase.countedCalls, count)
}
}
func TestParseHTTPResponseBodyJSON(t *testing.T) {
type myJSONStruct struct {

View File

@ -72,6 +72,14 @@ spec:
- STAGES
- STEPS
default: true
- name: maxRetries
type: int
description: Maximum number of HTTP request retries upon intermittend connetion interrupts
scope:
- PARAMETERS
- STAGES
- STEPS
default: 3
- name: password
type: string
description: The password to authenticate