github.com/xgoffin/jenkins-library@v1.154.0/cmd/integrationArtifactGetMplStatus.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7 "net/url" 8 9 "github.com/Jeffail/gabs/v2" 10 "github.com/SAP/jenkins-library/pkg/command" 11 "github.com/SAP/jenkins-library/pkg/cpi" 12 piperhttp "github.com/SAP/jenkins-library/pkg/http" 13 "github.com/SAP/jenkins-library/pkg/log" 14 "github.com/SAP/jenkins-library/pkg/telemetry" 15 "github.com/pkg/errors" 16 ) 17 18 type integrationArtifactGetMplStatusUtils interface { 19 command.ExecRunner 20 21 // Add more methods here, or embed additional interfaces, or remove/replace as required. 22 // The integrationArtifactGetMplStatusUtils interface should be descriptive of your runtime dependencies, 23 // i.e. include everything you need to be able to mock in tests. 24 // Unit tests shall be executable in parallel (not depend on global state), and don't (re-)test dependencies. 25 } 26 27 type integrationArtifactGetMplStatusUtilsBundle struct { 28 *command.Command 29 30 // Embed more structs as necessary to implement methods or interfaces you add to integrationArtifactGetMplStatusUtils. 31 // Structs embedded in this way must each have a unique set of methods attached. 32 // If there is no struct which implements the method you need, attach the method to 33 // integrationArtifactGetMplStatusUtilsBundle and forward to the implementation of the dependency. 34 } 35 36 func newIntegrationArtifactGetMplStatusUtils() integrationArtifactGetMplStatusUtils { 37 utils := integrationArtifactGetMplStatusUtilsBundle{ 38 Command: &command.Command{}, 39 } 40 // Reroute command output to logging framework 41 utils.Stdout(log.Writer()) 42 utils.Stderr(log.Writer()) 43 return &utils 44 } 45 46 func integrationArtifactGetMplStatus(config integrationArtifactGetMplStatusOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *integrationArtifactGetMplStatusCommonPipelineEnvironment) { 47 // Utils can be used wherever the command.ExecRunner interface is expected. 48 // It can also be used for example as a mavenExecRunner. 49 httpClient := &piperhttp.Client{} 50 // For HTTP calls import piperhttp "github.com/SAP/jenkins-library/pkg/http" 51 // and use a &piperhttp.Client{} in a custom system 52 // Example: step checkmarxExecuteScan.go 53 54 // Error situations should be bubbled up until they reach the line below which will then stop execution 55 // through the log.Entry().Fatal() call leading to an os.Exit(1) in the end. 56 err := runIntegrationArtifactGetMplStatus(&config, telemetryData, httpClient, commonPipelineEnvironment) 57 if err != nil { 58 log.Entry().WithError(err).Fatal("step execution failed") 59 } 60 } 61 62 func runIntegrationArtifactGetMplStatus( 63 config *integrationArtifactGetMplStatusOptions, 64 telemetryData *telemetry.CustomData, 65 httpClient piperhttp.Sender, 66 commonPipelineEnvironment *integrationArtifactGetMplStatusCommonPipelineEnvironment) error { 67 68 serviceKey, err := cpi.ReadCpiServiceKey(config.APIServiceKey) 69 if err != nil { 70 return err 71 } 72 73 clientOptions := piperhttp.ClientOptions{} 74 httpClient.SetOptions(clientOptions) 75 header := make(http.Header) 76 header.Add("Accept", "application/json") 77 mplStatusEncodedURL := fmt.Sprintf("%s/api/v1/MessageProcessingLogs?$filter=IntegrationArtifact/Id"+url.QueryEscape(" eq ")+"'%s'"+ 78 url.QueryEscape(" and Status ne ")+"'DISCARDED'"+"&$orderby="+url.QueryEscape("LogEnd desc")+"&$top=1", serviceKey.OAuth.Host, config.IntegrationFlowID) 79 tokenParameters := cpi.TokenParameters{TokenURL: serviceKey.OAuth.OAuthTokenProviderURL, Username: serviceKey.OAuth.ClientID, Password: serviceKey.OAuth.ClientSecret, Client: httpClient} 80 token, err := cpi.CommonUtils.GetBearerToken(tokenParameters) 81 if err != nil { 82 return errors.Wrap(err, "failed to fetch Bearer Token") 83 } 84 clientOptions.Token = fmt.Sprintf("Bearer %s", token) 85 httpClient.SetOptions(clientOptions) 86 httpMethod := "GET" 87 mplStatusResp, httpErr := httpClient.SendRequest(httpMethod, mplStatusEncodedURL, nil, header, nil) 88 if httpErr != nil { 89 return errors.Wrapf(httpErr, "HTTP %v request to %v failed with error", httpMethod, mplStatusEncodedURL) 90 } 91 92 if mplStatusResp != nil && mplStatusResp.Body != nil { 93 defer mplStatusResp.Body.Close() 94 } 95 96 if mplStatusResp == nil { 97 return errors.Errorf("did not retrieve a HTTP response: %v", httpErr) 98 } 99 100 if mplStatusResp.StatusCode == 200 { 101 bodyText, readErr := ioutil.ReadAll(mplStatusResp.Body) 102 if readErr != nil { 103 return errors.Wrap(readErr, "HTTP response body could not be read") 104 } 105 jsonResponse, parsingErr := gabs.ParseJSON([]byte(bodyText)) 106 if parsingErr != nil { 107 return errors.Wrapf(parsingErr, "HTTP response body could not be parsed as JSON: %v", string(bodyText)) 108 } 109 if jsonResponse == nil { 110 return errors.Errorf("Empty json response: %v", string(bodyText)) 111 } 112 if jsonResponse.Exists("d", "results", "0") { 113 mplStatus := jsonResponse.Path("d.results.0.Status").Data().(string) 114 commonPipelineEnvironment.custom.integrationFlowMplStatus = mplStatus 115 116 //if error, then return immediately with the error details 117 if mplStatus == "FAILED" { 118 mplID := jsonResponse.Path("d.results.0.MessageGuid").Data().(string) 119 resp, err := getIntegrationArtifactMPLError(commonPipelineEnvironment, mplID, httpClient, serviceKey.OAuth.Host) 120 if err != nil { 121 return err 122 } 123 return errors.New(resp) 124 } 125 } 126 return nil 127 } 128 responseBody, readErr := ioutil.ReadAll(mplStatusResp.Body) 129 130 if readErr != nil { 131 return errors.Wrapf(readErr, "HTTP response body could not be read, Response status code: %v", mplStatusResp.StatusCode) 132 } 133 134 log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code: %v", string(responseBody), mplStatusResp.StatusCode) 135 return errors.Errorf("Unable to get integration flow MPL status, Response Status code: %v", mplStatusResp.StatusCode) 136 } 137 138 //getIntegrationArtifactMPLError - Get integration artifact MPL error details 139 func getIntegrationArtifactMPLError(commonPipelineEnvironment *integrationArtifactGetMplStatusCommonPipelineEnvironment, mplID string, httpClient piperhttp.Sender, apiHost string) (string, error) { 140 httpMethod := "GET" 141 header := make(http.Header) 142 header.Add("content-type", "application/json") 143 errorStatusURL := fmt.Sprintf("%s/api/v1/MessageProcessingLogs('%s')/ErrorInformation/$value", apiHost, mplID) 144 errorStatusResp, httpErr := httpClient.SendRequest(httpMethod, errorStatusURL, nil, header, nil) 145 146 if errorStatusResp != nil && errorStatusResp.Body != nil { 147 defer errorStatusResp.Body.Close() 148 } 149 150 if errorStatusResp == nil { 151 return "", errors.Errorf("did not retrieve a HTTP response: %v", httpErr) 152 } 153 154 if errorStatusResp.StatusCode == http.StatusOK { 155 log.Entry(). 156 WithField("MPLID", mplID). 157 Info("Successfully retrieved Integration Flow artefact message processing error") 158 responseBody, readErr := ioutil.ReadAll(errorStatusResp.Body) 159 if readErr != nil { 160 return "", errors.Wrapf(readErr, "HTTP response body could not be read, response status code: %v", errorStatusResp.StatusCode) 161 } 162 mplErrorDetails := string(responseBody) 163 commonPipelineEnvironment.custom.integrationFlowMplError = mplErrorDetails 164 return mplErrorDetails, nil 165 } 166 if httpErr != nil { 167 return getHTTPErrorMessage(httpErr, errorStatusResp, httpMethod, errorStatusURL) 168 } 169 return "", errors.Errorf("failed to get Integration Flow artefact message processing error, response Status code: %v", errorStatusResp.StatusCode) 170 }