2021-08-12 09:11:02 +02:00
package cmd
import (
"bytes"
b64 "encoding/base64"
"encoding/json"
"fmt"
2023-08-16 12:57:04 +02:00
"io"
2021-08-12 09:11:02 +02:00
"net/http"
"path/filepath"
"strings"
"github.com/Jeffail/gabs/v2"
"github.com/SAP/jenkins-library/pkg/cpi"
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/pkg/errors"
)
type integrationArtifactResourceData struct {
Method string
URL string
IFlowID string
ScsMessage string
FlrMessage string
StatusCode int
}
func integrationArtifactResource ( config integrationArtifactResourceOptions , telemetryData * telemetry . CustomData ) {
// Utils can be used wherever the command.ExecRunner interface is expected.
// It can also be used for example as a mavenExecRunner.
httpClient := & piperhttp . Client { }
fileUtils := & piperutils . Files { }
// 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 be bubbled up until they reach the line below which will then stop execution
// through the log.Entry().Fatal() call leading to an os.Exit(1) in the end.
err := runIntegrationArtifactResource ( & config , telemetryData , fileUtils , httpClient )
if err != nil {
log . Entry ( ) . WithError ( err ) . Fatal ( "step execution failed" )
}
}
func runIntegrationArtifactResource ( config * integrationArtifactResourceOptions , telemetryData * telemetry . CustomData , fileUtils piperutils . FileUtils , httpClient piperhttp . Sender ) error {
serviceKey , err := cpi . ReadCpiServiceKey ( config . APIServiceKey )
if err != nil {
return err
}
clientOptions := piperhttp . ClientOptions { }
header := make ( http . Header )
header . Add ( "Accept" , "application/json" )
tokenParameters := cpi . TokenParameters { TokenURL : serviceKey . OAuth . OAuthTokenProviderURL , Username : serviceKey . OAuth . ClientID , Password : serviceKey . OAuth . ClientSecret , Client : httpClient }
token , err := cpi . CommonUtils . GetBearerToken ( tokenParameters )
if err != nil {
return errors . Wrap ( err , "failed to fetch Bearer Token" )
}
clientOptions . Token = fmt . Sprintf ( "Bearer %s" , token )
httpClient . SetOptions ( clientOptions )
mode := strings . ToLower ( strings . TrimSpace ( config . Operation ) )
switch mode {
case "create" :
return UploadIntegrationArtifactResource ( config , httpClient , fileUtils , serviceKey . OAuth . Host )
case "update" :
return UpdateIntegrationArtifactResource ( config , httpClient , fileUtils , serviceKey . OAuth . Host )
case "delete" :
return DeleteIntegrationArtifactResource ( config , httpClient , fileUtils , serviceKey . OAuth . Host )
default :
return errors . New ( "invalid input for resource operation" )
}
}
2022-11-08 09:47:38 +02:00
// UploadIntegrationArtifactResource - Upload new resource file to existing integration flow design time artefact
2021-08-12 09:11:02 +02:00
func UploadIntegrationArtifactResource ( config * integrationArtifactResourceOptions , httpClient piperhttp . Sender , fileUtils piperutils . FileUtils , apiHost string ) error {
httpMethod := "POST"
uploadIflowStatusURL := fmt . Sprintf ( "%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')/Resources" , apiHost , config . IntegrationFlowID , "Active" )
header := make ( http . Header )
header . Add ( "content-type" , "application/json" )
payload , jsonError := GetJSONPayload ( config , "create" , fileUtils )
if jsonError != nil {
return errors . Wrapf ( jsonError , "Failed to get json payload for file %v, failed with error" , config . ResourcePath )
}
uploadIflowStatusResp , httpErr := httpClient . SendRequest ( httpMethod , uploadIflowStatusURL , payload , header , nil )
successMessage := "Successfully create a new resource file in the integration flow artefact"
failureMessage := "Failed to create a new resource file in the integration flow artefact"
integrationArtifactResourceData := integrationArtifactResourceData {
Method : httpMethod ,
URL : uploadIflowStatusURL ,
IFlowID : config . IntegrationFlowID ,
ScsMessage : successMessage ,
FlrMessage : failureMessage ,
StatusCode : http . StatusCreated ,
}
return HttpResponseHandler ( uploadIflowStatusResp , httpErr , & integrationArtifactResourceData )
}
2022-11-08 09:47:38 +02:00
// UpdateIntegrationArtifactResource - Update integration artifact resource file
2021-08-12 09:11:02 +02:00
func UpdateIntegrationArtifactResource ( config * integrationArtifactResourceOptions , httpClient piperhttp . Sender , fileUtils piperutils . FileUtils , apiHost string ) error {
httpMethod := "PUT"
header := make ( http . Header )
header . Add ( "content-type" , "application/json" )
fileName := filepath . Base ( config . ResourcePath )
fileExt := GetResourceFileExtension ( fileName )
if fileExt == "" {
return errors . New ( "invalid file extension in resource file" )
}
updateIflowStatusURL := fmt . Sprintf ( "%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')/$links/Resources(Name='%s',ResourceType='%s')" , apiHost , config . IntegrationFlowID , "Active" , fileName , fileExt )
payload , jsonError := GetJSONPayload ( config , "update" , fileUtils )
if jsonError != nil {
return errors . Wrapf ( jsonError , "Failed to get json payload for file %v, failed with error" , config . ResourcePath )
}
updateIflowStatusResp , httpErr := httpClient . SendRequest ( httpMethod , updateIflowStatusURL , payload , header , nil )
successMessage := "Successfully updated resource file of the integration flow artefact"
failureMessage := "Failed to update rsource file of the integration flow artefact"
integrationArtifactResourceData := integrationArtifactResourceData {
Method : httpMethod ,
URL : updateIflowStatusURL ,
IFlowID : config . IntegrationFlowID ,
ScsMessage : successMessage ,
FlrMessage : failureMessage ,
StatusCode : http . StatusOK ,
}
return HttpResponseHandler ( updateIflowStatusResp , httpErr , & integrationArtifactResourceData )
}
2022-11-08 09:47:38 +02:00
// DeleteIntegrationArtifactResource - Delete integration artifact resource file
2021-08-12 09:11:02 +02:00
func DeleteIntegrationArtifactResource ( config * integrationArtifactResourceOptions , httpClient piperhttp . Sender , fileUtils piperutils . FileUtils , apiHost string ) error {
httpMethod := "DELETE"
header := make ( http . Header )
header . Add ( "content-type" , "application/json" )
fileName := filepath . Base ( config . ResourcePath )
fileExt := GetResourceFileExtension ( fileName )
if fileExt == "" {
return errors . New ( "invalid file extension in resource file" )
}
deleteIflowResourceStatusURL := fmt . Sprintf ( "%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')/$links/Resources(Name='%s',ResourceType='%s')" , apiHost , config . IntegrationFlowID , "Active" , fileName , fileExt )
deleteIflowResourceStatusResp , httpErr := httpClient . SendRequest ( httpMethod , deleteIflowResourceStatusURL , nil , header , nil )
successMessage := "Successfully deleted a resource file in the integration flow artefact"
failureMessage := "Failed to delete a resource file in the integration flow artefact"
integrationArtifactResourceData := integrationArtifactResourceData {
Method : httpMethod ,
URL : deleteIflowResourceStatusURL ,
IFlowID : config . IntegrationFlowID ,
ScsMessage : successMessage ,
FlrMessage : failureMessage ,
StatusCode : http . StatusOK ,
}
return HttpResponseHandler ( deleteIflowResourceStatusResp , httpErr , & integrationArtifactResourceData )
}
2022-11-08 09:47:38 +02:00
// GetJSONPayload -return http payload as byte array
2021-08-12 09:11:02 +02:00
func GetJSONPayload ( config * integrationArtifactResourceOptions , mode string , fileUtils piperutils . FileUtils ) ( * bytes . Buffer , error ) {
fileContent , readError := fileUtils . FileRead ( config . ResourcePath )
if readError != nil {
return nil , errors . Wrapf ( readError , "Error reading file" )
}
fileName := filepath . Base ( config . ResourcePath )
jsonObj := gabs . New ( )
if mode == "create" {
jsonObj . Set ( fileName , "Name" )
jsonObj . Set ( GetResourceFileExtension ( fileName ) , "ResourceType" )
jsonObj . Set ( b64 . StdEncoding . EncodeToString ( fileContent ) , "ResourceContent" )
} else if mode == "update" {
jsonObj . Set ( b64 . StdEncoding . EncodeToString ( fileContent ) , "ResourceContent" )
} else {
return nil , fmt . Errorf ( "Unkown node: '%s'" , mode )
}
jsonBody , jsonErr := json . Marshal ( jsonObj )
if jsonErr != nil {
return nil , errors . Wrapf ( jsonErr , "json payload is invalid for integration flow artifact %q" , config . IntegrationFlowID )
}
return bytes . NewBuffer ( jsonBody ) , nil
}
2022-11-08 09:47:38 +02:00
// GetResourceFileExtension -return resource file extension
2021-08-12 09:11:02 +02:00
func GetResourceFileExtension ( filename string ) string {
fileExtension := filepath . Ext ( filename )
switch fileExtension {
case ".xsl" :
return "xslt"
case ".gsh" , ".groovy" :
return "groovy"
case ".js" :
return "js"
case ".jar" :
return "jar"
default :
return ""
}
}
2022-11-08 09:47:38 +02:00
// HttpResponseHandler - handle http response object
2021-08-12 09:11:02 +02:00
func HttpResponseHandler ( resp * http . Response , httpErr error , integrationArtifactResourceData * integrationArtifactResourceData ) error {
if resp != nil && resp . Body != nil {
defer resp . Body . Close ( )
}
if resp == nil {
return errors . Errorf ( "did not retrieve a HTTP response: %v" , httpErr )
}
if resp . StatusCode == integrationArtifactResourceData . StatusCode {
log . Entry ( ) .
WithField ( "IntegrationFlowID" , integrationArtifactResourceData . IFlowID ) .
Info ( integrationArtifactResourceData . ScsMessage )
return nil
}
if httpErr != nil {
2023-08-16 12:57:04 +02:00
responseBody , readErr := io . ReadAll ( resp . Body )
2021-08-12 09:11:02 +02:00
if readErr != nil {
return errors . Wrapf ( readErr , "HTTP response body could not be read, Response status code: %v" , resp . StatusCode )
}
2021-11-18 10:08:03 +02:00
log . Entry ( ) . Errorf ( "a HTTP error occurred! Response body: %v, Response status code: %v" , string ( responseBody ) , resp . StatusCode )
2021-08-12 09:11:02 +02:00
return errors . Wrapf ( httpErr , "HTTP %v request to %v failed with error: %v" , integrationArtifactResourceData . Method , integrationArtifactResourceData . URL , string ( responseBody ) )
}
return errors . Errorf ( "%s, Response Status code: %v" , integrationArtifactResourceData . FlrMessage , resp . StatusCode )
}