1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/pkg/cpi/commonUtils.go

222 lines
7.8 KiB
Go
Raw Normal View History

package cpi
import (
CPI - Introduce service key (#2901) * Switch to service key for CPI GetMplStatus Introduces read method for service key files, mock utils and tests. * Use secret text instead of file * Change serviceKey definition * Update cpiUpload to use Service Key retrieved the host and uaa information from service key * Update cpiDeploy to use service key retrieved the host and uaa information from service key * Update cpiServiceEndpoint to use Service Key retrieved the host and uaa information from service key * Update cpiDownload to use Service Key retrieved the host and uaa information from service key * Update cpiUpdateConfig to use Service Key retrieved the host and uaa information from service key * Refactor serviceKey var name * Fixed references to service key to follow the real format they should be accessed through oauth instead of uaa because of the format of the json * Rename ServiceKey to APIServiceKey To support having a different service key(and for readability), we need to change the name to API. * Add STAGES and STEPS yaml add in to each yaml file of cpi integration * Revert "Add STAGES and STEPS yaml" This reverts commit aa2665d158b0f864cfee95ff999a7dc8ea3477f1. * Change comments/formatting commonUtils Make comments more understandable and follow code climate suggestions * Change documentation files for steps remove OAuth and host and change credentials to be servicekey Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com> Co-authored-by: Thorsten Duda <thorsten.duda@sap.com>
2021-06-28 10:50:33 +02:00
"encoding/json"
"fmt"
"io"
"mime"
"net/http"
"os"
"path/filepath"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/Jeffail/gabs/v2"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/pkg/errors"
)
2022-11-08 09:47:38 +02:00
// CommonUtils for CPI
type CommonUtils interface {
GetBearerToken() (string, error)
}
2022-11-08 09:47:38 +02:00
// HttpCPIUtils for CPI
type HttpCPIUtils interface {
HandleHTTPFileDownloadResponse() error
}
2022-11-08 09:47:38 +02:00
// HTTPUploadUtils for CPI
type HTTPUploadUtils interface {
HandleHTTPFileUploadResponse() error
HandleHTTPGetRequestResponse() (string, error)
}
2022-11-08 09:47:38 +02:00
// TokenParameters struct
type TokenParameters struct {
TokenURL, Username, Password string
Client piperhttp.Sender
}
2022-11-08 09:47:38 +02:00
// HttpParameters struct
type HttpFileDownloadRequestParameters struct {
ErrMessage, FileDownloadPath string
Response *http.Response
}
2022-11-08 09:47:38 +02:00
// HTTPFileUploadRequestParameters struct
type HttpFileUploadRequestParameters struct {
ErrMessage, FilePath, HTTPMethod, HTTPURL, SuccessMessage string
Response *http.Response
HTTPErr error
}
CPI - Introduce service key (#2901) * Switch to service key for CPI GetMplStatus Introduces read method for service key files, mock utils and tests. * Use secret text instead of file * Change serviceKey definition * Update cpiUpload to use Service Key retrieved the host and uaa information from service key * Update cpiDeploy to use service key retrieved the host and uaa information from service key * Update cpiServiceEndpoint to use Service Key retrieved the host and uaa information from service key * Update cpiDownload to use Service Key retrieved the host and uaa information from service key * Update cpiUpdateConfig to use Service Key retrieved the host and uaa information from service key * Refactor serviceKey var name * Fixed references to service key to follow the real format they should be accessed through oauth instead of uaa because of the format of the json * Rename ServiceKey to APIServiceKey To support having a different service key(and for readability), we need to change the name to API. * Add STAGES and STEPS yaml add in to each yaml file of cpi integration * Revert "Add STAGES and STEPS yaml" This reverts commit aa2665d158b0f864cfee95ff999a7dc8ea3477f1. * Change comments/formatting commonUtils Make comments more understandable and follow code climate suggestions * Change documentation files for steps remove OAuth and host and change credentials to be servicekey Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com> Co-authored-by: Thorsten Duda <thorsten.duda@sap.com>
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
}
// 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 := io.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
}
// 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 := io.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)
}
// 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)
}
responseCode := response.StatusCode
if (responseCode == http.StatusOK) || (responseCode == http.StatusCreated) {
log.Entry().
WithField("Created Artifact", httpFileUploadRequestParameters.FilePath).
Info(httpFileUploadRequestParameters.SuccessMessage)
return nil
}
if httpErr != nil {
responseBody, readErr := io.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)
}
// HandleHTTPGetRequestResponse - Handle the GET Request response data
func (httpGetRequestParameters HttpFileUploadRequestParameters) HandleHTTPGetRequestResponse() (string, error) {
response := httpGetRequestParameters.Response
httpErr := httpGetRequestParameters.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 {
responseBody, readErr := io.ReadAll(response.Body)
if readErr != nil {
return "", errors.Wrapf(readErr, "HTTP response body could not be read, response status code: %v", response.StatusCode)
}
return string(responseBody), nil
}
if httpErr != nil {
responseBody, readErr := io.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", httpGetRequestParameters.HTTPMethod, httpGetRequestParameters.HTTPURL, string(responseBody))
}
return "", errors.Errorf("%s, Response Status code: %v", httpGetRequestParameters.ErrMessage, response.StatusCode)
}