2021-01-12 13:17:42 +02:00
package cpi
import (
2021-06-28 10:50:33 +02:00
"encoding/json"
2021-01-12 13:17:42 +02:00
"fmt"
2021-11-02 11:30:08 +02:00
"io"
2021-01-12 13:17:42 +02:00
"io/ioutil"
2021-11-02 11:30:08 +02:00
"mime"
2021-01-12 13:17:42 +02:00
"net/http"
2021-11-02 11:30:08 +02:00
"os"
"path/filepath"
"github.com/SAP/jenkins-library/pkg/log"
2021-01-12 13:17:42 +02:00
"github.com/Jeffail/gabs/v2"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/pkg/errors"
)
//CommonUtils for CPI
type CommonUtils interface {
GetBearerToken ( ) ( string , error )
}
2021-11-02 11:30:08 +02:00
//HttpCPIUtils for CPI
type HttpCPIUtils interface {
HandleHTTPFileDownloadResponse ( ) error
}
2021-12-28 10:31:50 +02:00
//HTTPUploadUtils for CPI
type HTTPUploadUtils interface {
HandleHTTPFileUploadResponse ( ) error
}
2021-01-12 13:17:42 +02:00
//TokenParameters struct
type TokenParameters struct {
TokenURL , Username , Password string
Client piperhttp . Sender
}
2021-11-02 11:30:08 +02:00
//HttpParameters struct
type HttpFileDownloadRequestParameters struct {
ErrMessage , FileDownloadPath string
Response * http . Response
}
2021-12-28 10:31:50 +02:00
//HTTPFileUploadRequestParameters struct
type HttpFileUploadRequestParameters struct {
ErrMessage , FilePath , HTTPMethod , HTTPURL , SuccessMessage string
Response * http . Response
HTTPErr error
}
2021-06-28 10:50:33 +02:00
// ServiceKey contains information about a CPI service key
type ServiceKey struct {
OAuth OAuth ` json:"oauth" `
}
// OAuth is inside a CPI service key and contains more needed information
type OAuth struct {
Host string ` json:"url" `
OAuthTokenProviderURL string ` json:"tokenurl" `
ClientID string ` json:"clientid" `
ClientSecret string ` json:"clientsecret" `
}
// ReadCpiServiceKey unmarshalls the give json service key string.
func ReadCpiServiceKey ( serviceKeyJSON string ) ( cpiServiceKey ServiceKey , err error ) {
// parse
err = json . Unmarshal ( [ ] byte ( serviceKeyJSON ) , & cpiServiceKey )
if err != nil {
err = errors . Wrap ( err , "error unmarshalling serviceKey" )
return
}
log . Entry ( ) . Info ( "CPI serviceKey read successfully" )
return
}
2021-01-12 13:17:42 +02:00
// GetBearerToken -Provides the bearer token for making CPI OData calls
func ( tokenParameters TokenParameters ) GetBearerToken ( ) ( string , error ) {
httpClient := tokenParameters . Client
clientOptions := piperhttp . ClientOptions {
Username : tokenParameters . Username ,
Password : tokenParameters . Password ,
}
httpClient . SetOptions ( clientOptions )
header := make ( http . Header )
header . Add ( "Accept" , "application/json" )
tokenFinalURL := fmt . Sprintf ( "%s?grant_type=client_credentials" , tokenParameters . TokenURL )
method := "POST"
resp , httpErr := httpClient . SendRequest ( method , tokenFinalURL , nil , header , nil )
if httpErr != nil {
return "" , errors . Wrapf ( httpErr , "HTTP %v request to %v failed with error" , method , tokenFinalURL )
}
if resp != nil && resp . Body != nil {
defer resp . Body . Close ( )
}
if resp == nil {
return "" , errors . Errorf ( "did not retrieve a HTTP response" )
}
if resp . StatusCode != 200 {
return "" , errors . Errorf ( "did not retrieve a valid HTTP response code: %v" , httpErr )
}
bodyText , readErr := ioutil . ReadAll ( resp . Body )
if readErr != nil {
return "" , errors . Wrap ( readErr , "HTTP response body could not be read" )
}
jsonResponse , parsingErr := gabs . ParseJSON ( [ ] byte ( bodyText ) )
if parsingErr != nil {
return "" , errors . Wrapf ( parsingErr , "HTTP response body could not be parsed as JSON: %v" , string ( bodyText ) )
}
token := jsonResponse . Path ( "access_token" ) . Data ( ) . ( string )
return token , nil
}
2021-11-02 11:30:08 +02:00
// HandleHTTPFileDownloadResponse - Handle the file download response for http multipart response
func ( httpFileDownloadRequestParameters HttpFileDownloadRequestParameters ) HandleHTTPFileDownloadResponse ( ) error {
response := httpFileDownloadRequestParameters . Response
contentDisposition := response . Header . Get ( "Content-Disposition" )
disposition , params , err := mime . ParseMediaType ( contentDisposition )
if err != nil {
return errors . Wrapf ( err , "failed to read filename from http response headers, Content-Disposition %s" , disposition )
}
filename := params [ "filename" ]
if response != nil && response . Body != nil {
defer response . Body . Close ( )
}
if response . StatusCode == 200 {
workspaceRelativePath := httpFileDownloadRequestParameters . FileDownloadPath
err = os . MkdirAll ( workspaceRelativePath , 0755 )
// handling error while creating a workspce directoy for file download, if one not exist already!
if err != nil {
return errors . Wrapf ( err , "Failed to create workspace directory" )
}
zipFileName := filepath . Join ( workspaceRelativePath , filename )
file , err := os . Create ( zipFileName )
// handling error while creating a file in the filesystem
if err != nil {
return errors . Wrap ( err , "failed to create zip archive of api proxy" )
}
_ , err = io . Copy ( file , response . Body )
if err != nil {
return err
}
return nil
}
responseBody , readErr := ioutil . ReadAll ( response . Body )
if readErr != nil {
return errors . Wrapf ( readErr , "HTTP response body could not be read, Response status code: %v" , response . StatusCode )
}
log . Entry ( ) . Errorf ( "a HTTP error occurred! Response body: %v, Response status code : %v" , responseBody , response . StatusCode )
return errors . Errorf ( "%s, Response Status code: %v" , httpFileDownloadRequestParameters . ErrMessage , response . StatusCode )
}
2021-12-28 10:31:50 +02:00
// HandleHTTPFileUploadResponse - Handle the file upload response
func ( httpFileUploadRequestParameters HttpFileUploadRequestParameters ) HandleHTTPFileUploadResponse ( ) error {
response := httpFileUploadRequestParameters . Response
httpErr := httpFileUploadRequestParameters . HTTPErr
if response != nil && response . Body != nil {
defer response . Body . Close ( )
}
if response == nil {
return errors . Errorf ( "did not retrieve a HTTP response: %v" , httpErr )
}
if response . StatusCode == http . StatusOK {
log . Entry ( ) .
WithField ( "Created Artifact" , httpFileUploadRequestParameters . FilePath ) .
Info ( httpFileUploadRequestParameters . SuccessMessage )
return nil
}
if httpErr != nil {
responseBody , readErr := ioutil . ReadAll ( response . Body )
if readErr != nil {
return errors . Wrapf ( readErr , "HTTP response body could not be read, Response status code: %v" , response . StatusCode )
}
log . Entry ( ) . Errorf ( "a HTTP error occurred! Response body: %v, Response status code: %v" , string ( responseBody ) , response . StatusCode )
return errors . Wrapf ( httpErr , "HTTP %v request to %v failed with error: %v" , httpFileUploadRequestParameters . HTTPMethod , httpFileUploadRequestParameters . HTTPURL , string ( responseBody ) )
}
return errors . Errorf ( "%s, Response Status code: %v" , httpFileUploadRequestParameters . ErrMessage , response . StatusCode )
}