github.com/SAP/jenkins-library@v1.362.0/cmd/integrationArtifactUpload.go (about) 1 package cmd 2 3 import ( 4 "bytes" 5 b64 "encoding/base64" 6 "encoding/json" 7 "fmt" 8 "io" 9 "net/http" 10 11 "github.com/Jeffail/gabs/v2" 12 "github.com/SAP/jenkins-library/pkg/cpi" 13 piperhttp "github.com/SAP/jenkins-library/pkg/http" 14 "github.com/SAP/jenkins-library/pkg/log" 15 "github.com/SAP/jenkins-library/pkg/piperutils" 16 "github.com/SAP/jenkins-library/pkg/telemetry" 17 "github.com/pkg/errors" 18 ) 19 20 func integrationArtifactUpload(config integrationArtifactUploadOptions, telemetryData *telemetry.CustomData) { 21 // Utils can be used wherever the command.ExecRunner interface is expected. 22 // It can also be used for example as a mavenExecRunner. 23 httpClient := &piperhttp.Client{} 24 fileUtils := &piperutils.Files{} 25 // For HTTP calls import piperhttp "github.com/SAP/jenkins-library/pkg/http" 26 // and use a &piperhttp.Client{} in a custom system 27 // Example: step checkmarxExecuteScan.go 28 29 // Error situations should be bubbled up until they reach the line below which will then stop execution 30 // through the log.Entry().Fatal() call leading to an os.Exit(1) in the end. 31 err := runIntegrationArtifactUpload(&config, telemetryData, fileUtils, httpClient) 32 if err != nil { 33 log.Entry().WithError(err).Fatal("step execution failed") 34 } 35 } 36 37 func runIntegrationArtifactUpload(config *integrationArtifactUploadOptions, telemetryData *telemetry.CustomData, fileUtils piperutils.FileUtils, httpClient piperhttp.Sender) error { 38 39 serviceKey, err := cpi.ReadCpiServiceKey(config.APIServiceKey) 40 if err != nil { 41 return err 42 } 43 44 clientOptions := piperhttp.ClientOptions{} 45 header := make(http.Header) 46 header.Add("Accept", "application/json") 47 iFlowStatusServiceURL := fmt.Sprintf("%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')", serviceKey.OAuth.Host, config.IntegrationFlowID, "Active") 48 tokenParameters := cpi.TokenParameters{TokenURL: serviceKey.OAuth.OAuthTokenProviderURL, Username: serviceKey.OAuth.ClientID, Password: serviceKey.OAuth.ClientSecret, Client: httpClient} 49 token, err := cpi.CommonUtils.GetBearerToken(tokenParameters) 50 if err != nil { 51 return errors.Wrap(err, "failed to fetch Bearer Token") 52 } 53 clientOptions.Token = fmt.Sprintf("Bearer %s", token) 54 httpClient.SetOptions(clientOptions) 55 httpMethod := "GET" 56 57 //Check availability of integration artefact in CPI design time 58 iFlowStatusResp, httpErr := httpClient.SendRequest(httpMethod, iFlowStatusServiceURL, nil, header, nil) 59 60 if iFlowStatusResp != nil && iFlowStatusResp.Body != nil { 61 defer iFlowStatusResp.Body.Close() 62 } 63 if iFlowStatusResp.StatusCode == 200 { 64 return UpdateIntegrationArtifact(config, httpClient, fileUtils, serviceKey.OAuth.Host) 65 } else if httpErr != nil && iFlowStatusResp.StatusCode == 404 { 66 return UploadIntegrationArtifact(config, httpClient, fileUtils, serviceKey.OAuth.Host) 67 } 68 69 if iFlowStatusResp == nil { 70 return errors.Errorf("did not retrieve a HTTP response: %v", httpErr) 71 } 72 73 if httpErr != nil { 74 responseBody, readErr := io.ReadAll(iFlowStatusResp.Body) 75 if readErr != nil { 76 return errors.Wrapf(readErr, "HTTP response body could not be read, Response status code: %v", iFlowStatusResp.StatusCode) 77 } 78 log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code: %v", responseBody, iFlowStatusResp.StatusCode) 79 return errors.Wrapf(httpErr, "HTTP %v request to %v failed with error: %v", httpMethod, iFlowStatusServiceURL, string(responseBody)) 80 } 81 return errors.Errorf("Failed to check integration flow availability, Response Status code: %v", iFlowStatusResp.StatusCode) 82 } 83 84 // UploadIntegrationArtifact - Upload new integration artifact 85 func UploadIntegrationArtifact(config *integrationArtifactUploadOptions, httpClient piperhttp.Sender, fileUtils piperutils.FileUtils, apiHost string) error { 86 httpMethod := "POST" 87 uploadIflowStatusURL := fmt.Sprintf("%s/api/v1/IntegrationDesigntimeArtifacts", apiHost) 88 header := make(http.Header) 89 header.Add("content-type", "application/json") 90 payload, jsonError := GetJSONPayloadAsByteArray(config, "create", fileUtils) 91 if jsonError != nil { 92 return errors.Wrapf(jsonError, "Failed to get json payload for file %v, failed with error", config.FilePath) 93 } 94 95 uploadIflowStatusResp, httpErr := httpClient.SendRequest(httpMethod, uploadIflowStatusURL, payload, header, nil) 96 97 if uploadIflowStatusResp != nil && uploadIflowStatusResp.Body != nil { 98 defer uploadIflowStatusResp.Body.Close() 99 } 100 101 if uploadIflowStatusResp == nil { 102 return errors.Errorf("did not retrieve a HTTP response: %v", httpErr) 103 } 104 105 if uploadIflowStatusResp.StatusCode == http.StatusCreated { 106 log.Entry(). 107 WithField("IntegrationFlowID", config.IntegrationFlowID). 108 Info("Successfully created integration flow artefact in CPI designtime") 109 return nil 110 } 111 if httpErr != nil { 112 responseBody, readErr := io.ReadAll(uploadIflowStatusResp.Body) 113 if readErr != nil { 114 return errors.Wrapf(readErr, "HTTP response body could not be read, Response status code: %v", uploadIflowStatusResp.StatusCode) 115 } 116 log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code: %v", responseBody, uploadIflowStatusResp.StatusCode) 117 return errors.Wrapf(httpErr, "HTTP %v request to %v failed with error: %v", httpMethod, uploadIflowStatusURL, string(responseBody)) 118 } 119 return errors.Errorf("Failed to create Integration Flow artefact, Response Status code: %v", uploadIflowStatusResp.StatusCode) 120 } 121 122 // UpdateIntegrationArtifact - Update existing integration artifact 123 func UpdateIntegrationArtifact(config *integrationArtifactUploadOptions, httpClient piperhttp.Sender, fileUtils piperutils.FileUtils, apiHost string) error { 124 httpMethod := "PUT" 125 header := make(http.Header) 126 header.Add("content-type", "application/json") 127 updateIflowStatusURL := fmt.Sprintf("%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')", apiHost, config.IntegrationFlowID, "Active") 128 payload, jsonError := GetJSONPayloadAsByteArray(config, "update", fileUtils) 129 if jsonError != nil { 130 return errors.Wrapf(jsonError, "Failed to get json payload for file %v, failed with error", config.FilePath) 131 } 132 updateIflowStatusResp, httpErr := httpClient.SendRequest(httpMethod, updateIflowStatusURL, payload, header, nil) 133 134 if updateIflowStatusResp != nil && updateIflowStatusResp.Body != nil { 135 defer updateIflowStatusResp.Body.Close() 136 } 137 138 if updateIflowStatusResp == nil { 139 return errors.Errorf("did not retrieve a HTTP response: %v", httpErr) 140 } 141 142 if updateIflowStatusResp.StatusCode == http.StatusOK { 143 log.Entry(). 144 WithField("IntegrationFlowID", config.IntegrationFlowID). 145 Info("Successfully updated integration flow artefact in CPI designtime") 146 return nil 147 } 148 if httpErr != nil { 149 responseBody, readErr := io.ReadAll(updateIflowStatusResp.Body) 150 if readErr != nil { 151 return errors.Wrapf(readErr, "HTTP response body could not be read, Response status code: %v", updateIflowStatusResp.StatusCode) 152 } 153 log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code: %v", string(responseBody), updateIflowStatusResp.StatusCode) 154 return errors.Wrapf(httpErr, "HTTP %v request to %v failed with error: %v", httpMethod, updateIflowStatusURL, string(responseBody)) 155 } 156 return errors.Errorf("Failed to update Integration Flow artefact, Response Status code: %v", updateIflowStatusResp.StatusCode) 157 } 158 159 // GetJSONPayloadAsByteArray -return http payload as byte array 160 func GetJSONPayloadAsByteArray(config *integrationArtifactUploadOptions, mode string, fileUtils piperutils.FileUtils) (*bytes.Buffer, error) { 161 fileContent, readError := fileUtils.FileRead(config.FilePath) 162 if readError != nil { 163 return nil, errors.Wrapf(readError, "Error reading file") 164 } 165 jsonObj := gabs.New() 166 if mode == "create" { 167 jsonObj.Set(config.IntegrationFlowName, "Name") 168 jsonObj.Set(config.IntegrationFlowID, "Id") 169 jsonObj.Set(config.PackageID, "PackageId") 170 jsonObj.Set(b64.StdEncoding.EncodeToString(fileContent), "ArtifactContent") 171 } else if mode == "update" { 172 jsonObj.Set(config.IntegrationFlowName, "Name") 173 jsonObj.Set(b64.StdEncoding.EncodeToString(fileContent), "ArtifactContent") 174 } else { 175 return nil, fmt.Errorf("Unkown node: '%s'", mode) 176 } 177 178 jsonBody, jsonErr := json.Marshal(jsonObj) 179 180 if jsonErr != nil { 181 return nil, errors.Wrapf(jsonErr, "json payload is invalid for integration flow artifact %q", config.IntegrationFlowID) 182 } 183 return bytes.NewBuffer(jsonBody), nil 184 }