mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
228 lines
9.3 KiB
Go
228 lines
9.3 KiB
Go
|
package cmd
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"math/rand"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"github.com/Jeffail/gabs/v2"
|
||
|
"github.com/SAP/jenkins-library/pkg/apim"
|
||
|
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
func integrationArtifactTransport(config integrationArtifactTransportOptions, telemetryData *telemetry.CustomData) {
|
||
|
httpClient := &piperhttp.Client{}
|
||
|
err := runIntegrationArtifactTransport(&config, telemetryData, httpClient)
|
||
|
if err != nil {
|
||
|
log.Entry().WithError(err).Fatal("step execution failed")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func runIntegrationArtifactTransport(config *integrationArtifactTransportOptions, telemetryData *telemetry.CustomData, httpClient piperhttp.Sender) error {
|
||
|
apimData := apim.Bundle{APIServiceKey: config.CasServiceKey, Client: httpClient}
|
||
|
err := apim.Utils.InitAPIM(&apimData)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return CreateIntegrationArtifactTransportRequest(config, apimData)
|
||
|
}
|
||
|
|
||
|
//CreateIntegrationArtifactTransportRequest - Create a transport request for Integration Package
|
||
|
func CreateIntegrationArtifactTransportRequest(config *integrationArtifactTransportOptions, apistruct apim.Bundle) error {
|
||
|
httpMethod := http.MethodPost
|
||
|
httpClient := apistruct.Client
|
||
|
createTransportRequestURL := fmt.Sprintf("%s/v1/contentResources/export", apistruct.Host)
|
||
|
header := make(http.Header)
|
||
|
header.Add("content-type", "application/json")
|
||
|
payload, jsonError := GetCPITransportReqPayload(config)
|
||
|
if jsonError != nil {
|
||
|
return errors.Wrapf(jsonError, "Failed to get json payload for file %v, failed with error", config.IntegrationPackageID)
|
||
|
}
|
||
|
|
||
|
createTransportRequestResp, httpErr := httpClient.SendRequest(httpMethod, createTransportRequestURL, payload, header, nil)
|
||
|
|
||
|
if httpErr != nil {
|
||
|
return errors.Wrapf(httpErr, "HTTP %v request to %v failed with error", httpMethod, createTransportRequestURL)
|
||
|
}
|
||
|
|
||
|
if createTransportRequestResp != nil && createTransportRequestResp.Body != nil {
|
||
|
defer createTransportRequestResp.Body.Close()
|
||
|
}
|
||
|
|
||
|
if createTransportRequestResp == nil {
|
||
|
return errors.Errorf("did not retrieve a HTTP response")
|
||
|
}
|
||
|
|
||
|
if createTransportRequestResp.StatusCode == http.StatusAccepted {
|
||
|
log.Entry().
|
||
|
WithField("IntegrationPackageID", config.IntegrationPackageID).
|
||
|
Info("successfully created the integration package transport request")
|
||
|
|
||
|
bodyText, readErr := ioutil.ReadAll(createTransportRequestResp.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))
|
||
|
}
|
||
|
processId := jsonResponse.Path("processId").Data().(string)
|
||
|
|
||
|
if processId != "" {
|
||
|
error := pollTransportStatus(processId, retryCount, config, httpClient, apistruct.Host)
|
||
|
return error
|
||
|
}
|
||
|
return errors.New("Invalid process id")
|
||
|
}
|
||
|
responseBody, readErr := ioutil.ReadAll(createTransportRequestResp.Body)
|
||
|
|
||
|
if readErr != nil {
|
||
|
return errors.Wrapf(readErr, "HTTP response body could not be read, response status code: %v", createTransportRequestResp.StatusCode)
|
||
|
}
|
||
|
log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code : %v", string(responseBody), createTransportRequestResp.StatusCode)
|
||
|
return errors.Errorf("integration flow deployment failed, response Status code: %v", createTransportRequestResp.StatusCode)
|
||
|
}
|
||
|
|
||
|
//pollTransportStatus - Poll the integration package transport processing, return status or error details
|
||
|
func pollTransportStatus(processId string, remainingRetries int, config *integrationArtifactTransportOptions, httpClient piperhttp.Sender, apiHost string) error {
|
||
|
|
||
|
if remainingRetries <= 0 {
|
||
|
return errors.New("failed to start integration artifact after retrying several times")
|
||
|
}
|
||
|
transportStatus, err := getIntegrationTransportProcessingStatus(config, httpClient, apiHost, processId)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
//with specific delay between each retry
|
||
|
if (transportStatus == "RUNNING") || (transportStatus == "INITIAL") {
|
||
|
// Calling Sleep method
|
||
|
sleepTime := int(retryCount * 3)
|
||
|
time.Sleep(time.Duration(sleepTime) * time.Second)
|
||
|
remainingRetries--
|
||
|
return pollTransportStatus(processId, retryCount, config, httpClient, apiHost)
|
||
|
}
|
||
|
|
||
|
//if artifact transport completed, then just return
|
||
|
if transportStatus == "FINISHED" {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
//if error return immediately with error details
|
||
|
if transportStatus == "ERROR" || transportStatus == "ABORTED" {
|
||
|
resp, err := getIntegrationTransportError(config, httpClient, apiHost, processId)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return errors.New(resp)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
//GetJSONPayload -return http payload as byte array
|
||
|
func GetCPITransportReqPayload(config *integrationArtifactTransportOptions) (*bytes.Buffer, error) {
|
||
|
jsonObj := gabs.New()
|
||
|
jsonObj.Set(rand.Intn(5000), "id")
|
||
|
jsonObj.Set("MonitoringTeam", "requestor")
|
||
|
jsonObj.Set("1.0.0", "version")
|
||
|
jsonObj.Set("TransportManagementService", "exportMode")
|
||
|
jsonObj.Set("MTAR", "exportMediaType")
|
||
|
jsonObj.Set("Integration Artifact transport request for TransportManagementService", "description")
|
||
|
jsonResourceObj := gabs.New()
|
||
|
jsonResourceObj.Set(config.IntegrationPackageID, "id")
|
||
|
jsonResourceObj.Set(config.ResourceID, "resourceID")
|
||
|
jsonResourceObj.Set("d9c3fe08ceeb47a2991e53049f2ed766", "contentType")
|
||
|
jsonResourceObj.Set("package", "subType")
|
||
|
jsonResourceObj.Set(config.Name, "name")
|
||
|
jsonResourceObj.Set("CloudIntegration", "type")
|
||
|
jsonResourceObj.Set(config.Version, "version")
|
||
|
jsonObj.ArrayAppend(jsonResourceObj, "contentResources")
|
||
|
|
||
|
jsonBody, jsonErr := json.Marshal(jsonObj)
|
||
|
|
||
|
if jsonErr != nil {
|
||
|
return nil, errors.Wrapf(jsonErr, "Transport request payload is invalid for integration package artifact %q", config.IntegrationPackageID)
|
||
|
}
|
||
|
return bytes.NewBuffer(jsonBody), nil
|
||
|
}
|
||
|
|
||
|
//getIntegrationTransportProcessingStatus - Get integration package transport request processing Status
|
||
|
func getIntegrationTransportProcessingStatus(config *integrationArtifactTransportOptions, httpClient piperhttp.Sender, apiHost string, processId string) (string, error) {
|
||
|
httpMethod := "GET"
|
||
|
header := make(http.Header)
|
||
|
header.Add("content-type", "application/json")
|
||
|
header.Add("Accept", "application/json")
|
||
|
transportProcStatusURL := fmt.Sprintf("%s/v1/operations/%s", apiHost, processId)
|
||
|
transportProcStatusResp, httpErr := httpClient.SendRequest(httpMethod, transportProcStatusURL, nil, header, nil)
|
||
|
|
||
|
if transportProcStatusResp != nil && transportProcStatusResp.Body != nil {
|
||
|
defer transportProcStatusResp.Body.Close()
|
||
|
}
|
||
|
|
||
|
if transportProcStatusResp == nil {
|
||
|
return "", errors.Errorf("did not retrieve a HTTP response: %v", httpErr)
|
||
|
}
|
||
|
|
||
|
if (transportProcStatusResp.StatusCode == http.StatusOK) || (transportProcStatusResp.StatusCode == http.StatusAccepted) {
|
||
|
log.Entry().
|
||
|
WithField("IntegrationPackageID", config.IntegrationPackageID).
|
||
|
Info("successfully processed the integration package transport response status")
|
||
|
|
||
|
bodyText, readErr := ioutil.ReadAll(transportProcStatusResp.Body)
|
||
|
if readErr != nil {
|
||
|
return "", errors.Wrapf(readErr, "HTTP response body could not be read, response status code: %v", transportProcStatusResp.StatusCode)
|
||
|
}
|
||
|
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))
|
||
|
}
|
||
|
contentTransporStatus := jsonResponse.Path("state").Data().(string)
|
||
|
return contentTransporStatus, nil
|
||
|
}
|
||
|
if httpErr != nil {
|
||
|
return getHTTPErrorMessage(httpErr, transportProcStatusResp, httpMethod, transportProcStatusURL)
|
||
|
}
|
||
|
return "", errors.Errorf("failed to get transport request processing status, response Status code: %v", transportProcStatusResp.StatusCode)
|
||
|
}
|
||
|
|
||
|
//getTransportError - Get integration package transport failures error details
|
||
|
func getIntegrationTransportError(config *integrationArtifactTransportOptions, httpClient piperhttp.Sender, apiHost string, processId string) (string, error) {
|
||
|
httpMethod := "GET"
|
||
|
header := make(http.Header)
|
||
|
header.Add("content-type", "application/json")
|
||
|
errorStatusURL := fmt.Sprintf("%s/v1/operations/%s/logs", apiHost, processId)
|
||
|
errorStatusResp, httpErr := httpClient.SendRequest(httpMethod, errorStatusURL, nil, header, nil)
|
||
|
|
||
|
if errorStatusResp != nil && errorStatusResp.Body != nil {
|
||
|
defer errorStatusResp.Body.Close()
|
||
|
}
|
||
|
|
||
|
if errorStatusResp == nil {
|
||
|
return "", errors.Errorf("did not retrieve a HTTP response: %v", httpErr)
|
||
|
}
|
||
|
|
||
|
if errorStatusResp.StatusCode == http.StatusOK {
|
||
|
log.Entry().
|
||
|
WithField("IntegrationPackageId", config.IntegrationPackageID).
|
||
|
Info("Successfully retrieved deployment failures error details")
|
||
|
responseBody, readErr := ioutil.ReadAll(errorStatusResp.Body)
|
||
|
if readErr != nil {
|
||
|
return "", errors.Wrapf(readErr, "HTTP response body could not be read, response status code: %v", errorStatusResp.StatusCode)
|
||
|
}
|
||
|
log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code: %v", string(responseBody), errorStatusResp.StatusCode)
|
||
|
errorDetails := string(responseBody)
|
||
|
return errorDetails, nil
|
||
|
}
|
||
|
if httpErr != nil {
|
||
|
return getHTTPErrorMessage(httpErr, errorStatusResp, httpMethod, errorStatusURL)
|
||
|
}
|
||
|
return "", errors.Errorf("failed to get Integration Package transport error details, response Status code: %v", errorStatusResp.StatusCode)
|
||
|
}
|