mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
34fc844ac0
* Fix proxy usage in tmsUpload * Fix no default description if custom description is not provided
293 lines
10 KiB
Go
293 lines
10 KiB
Go
package cmd
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"sort"
|
|
"strconv"
|
|
|
|
"github.com/SAP/jenkins-library/pkg/command"
|
|
piperHttp "github.com/SAP/jenkins-library/pkg/http"
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
|
"github.com/SAP/jenkins-library/pkg/tms"
|
|
"github.com/ghodss/yaml"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type uaa struct {
|
|
Url string `json:"url"`
|
|
ClientId string `json:"clientid"`
|
|
ClientSecret string `json:"clientsecret"`
|
|
}
|
|
|
|
type serviceKey struct {
|
|
Uaa uaa `json:"uaa"`
|
|
Uri string `json:"uri"`
|
|
}
|
|
|
|
type tmsUploadUtils interface {
|
|
command.ExecRunner
|
|
|
|
FileExists(filename string) (bool, error)
|
|
FileRead(path string) ([]byte, error)
|
|
|
|
// Add more methods here, or embed additional interfaces, or remove/replace as required.
|
|
// The tmsUploadUtils interface should be descriptive of your runtime dependencies,
|
|
// i.e. include everything you need to be able to mock in tests.
|
|
// Unit tests shall be executable in parallel (not depend on global state), and don't (re-)test dependencies.
|
|
}
|
|
|
|
type tmsUploadUtilsBundle struct {
|
|
*command.Command
|
|
*piperutils.Files
|
|
|
|
// Embed more structs as necessary to implement methods or interfaces you add to tmsUploadUtils.
|
|
// Structs embedded in this way must each have a unique set of methods attached.
|
|
// If there is no struct which implements the method you need, attach the method to
|
|
// tmsUploadUtilsBundle and forward to the implementation of the dependency.
|
|
}
|
|
|
|
func newTmsUploadUtils() tmsUploadUtils {
|
|
utils := tmsUploadUtilsBundle{
|
|
Command: &command.Command{},
|
|
Files: &piperutils.Files{},
|
|
}
|
|
// Reroute command output to logging framework
|
|
utils.Stdout(log.Writer())
|
|
utils.Stderr(log.Writer())
|
|
return &utils
|
|
}
|
|
|
|
func tmsUpload(config tmsUploadOptions, telemetryData *telemetry.CustomData, influx *tmsUploadInflux) {
|
|
// Utils can be used wherever the command.ExecRunner interface is expected.
|
|
// It can also be used for example as a mavenExecRunner.
|
|
utils := newTmsUploadUtils()
|
|
client := &piperHttp.Client{}
|
|
proxy := config.Proxy
|
|
options := piperHttp.ClientOptions{}
|
|
if proxy != "" {
|
|
transportProxy, err := url.Parse(proxy)
|
|
if err != nil {
|
|
log.Entry().WithError(err).Fatalf("Failed to parse proxy string %v into a URL structure", proxy)
|
|
}
|
|
|
|
options = piperHttp.ClientOptions{TransportProxy: transportProxy}
|
|
client.SetOptions(options)
|
|
if GeneralConfig.Verbose {
|
|
log.Entry().Infof("HTTP client instructed to use %v proxy", proxy)
|
|
}
|
|
}
|
|
|
|
serviceKey, err := unmarshalServiceKey(config.TmsServiceKey)
|
|
if err != nil {
|
|
log.Entry().WithError(err).Fatal("Failed to unmarshal TMS service key")
|
|
}
|
|
|
|
if GeneralConfig.Verbose {
|
|
log.Entry().Info("Will be used for communication:")
|
|
log.Entry().Infof("- client id: %v", serviceKey.Uaa.ClientId)
|
|
log.Entry().Infof("- TMS URL: %v", serviceKey.Uri)
|
|
log.Entry().Infof("- UAA URL: %v", serviceKey.Uaa.Url)
|
|
}
|
|
|
|
communicationInstance, err := tms.NewCommunicationInstance(client, serviceKey.Uri, serviceKey.Uaa.Url, serviceKey.Uaa.ClientId, serviceKey.Uaa.ClientSecret, GeneralConfig.Verbose, options)
|
|
if err != nil {
|
|
log.Entry().WithError(err).Fatal("Failed to prepare client for talking with TMS")
|
|
}
|
|
|
|
if err := runTmsUpload(config, communicationInstance, utils); err != nil {
|
|
log.Entry().WithError(err).Fatal("Failed to run tmsUpload step")
|
|
}
|
|
}
|
|
|
|
func runTmsUpload(config tmsUploadOptions, communicationInstance tms.CommunicationInterface, utils tmsUploadUtils) error {
|
|
mtaPath := config.MtaPath
|
|
exists, _ := utils.FileExists(mtaPath)
|
|
if !exists {
|
|
log.SetErrorCategory(log.ErrorConfiguration)
|
|
return fmt.Errorf("mta file %s not found", mtaPath)
|
|
}
|
|
|
|
description := tms.DEFAULT_TR_DESCRIPTION
|
|
if config.CustomDescription != "" {
|
|
description = config.CustomDescription
|
|
}
|
|
namedUser := config.NamedUser
|
|
nodeName := config.NodeName
|
|
mtaVersion := config.MtaVersion
|
|
nodeNameExtDescriptorMapping := config.NodeExtDescriptorMapping
|
|
|
|
if GeneralConfig.Verbose {
|
|
log.Entry().Info("The step will use the following values:")
|
|
log.Entry().Infof("- description: %v", description)
|
|
|
|
if len(nodeNameExtDescriptorMapping) > 0 {
|
|
log.Entry().Infof("- mapping between node names and MTA extension descriptor file paths: %v", nodeNameExtDescriptorMapping)
|
|
}
|
|
log.Entry().Infof("- MTA path: %v", mtaPath)
|
|
log.Entry().Infof("- MTA version: %v", mtaVersion)
|
|
if namedUser != "" {
|
|
log.Entry().Infof("- named user: %v", namedUser)
|
|
}
|
|
log.Entry().Infof("- node name: %v", nodeName)
|
|
}
|
|
|
|
if len(nodeNameExtDescriptorMapping) > 0 {
|
|
nodes, errGetNodes := communicationInstance.GetNodes()
|
|
if errGetNodes != nil {
|
|
log.SetErrorCategory(log.ErrorService)
|
|
return fmt.Errorf("failed to get nodes: %w", errGetNodes)
|
|
}
|
|
|
|
mtaYamlMap, errGetMtaYamlAsMap := getYamlAsMap(utils, "mta.yaml")
|
|
if errGetMtaYamlAsMap != nil {
|
|
log.SetErrorCategory(log.ErrorConfiguration)
|
|
return fmt.Errorf("failed to get mta.yaml as map: %w", errGetMtaYamlAsMap)
|
|
}
|
|
_, isIdParameterInMap := mtaYamlMap["ID"]
|
|
_, isVersionParameterInMap := mtaYamlMap["version"]
|
|
if !isIdParameterInMap || !isVersionParameterInMap {
|
|
var errorMessage string
|
|
if !isIdParameterInMap {
|
|
errorMessage += "parameter 'ID' is not found in mta.yaml\n"
|
|
}
|
|
if !isVersionParameterInMap {
|
|
errorMessage += "parameter 'version' is not found in mta.yaml\n"
|
|
}
|
|
log.SetErrorCategory(log.ErrorConfiguration)
|
|
return errors.New(errorMessage)
|
|
}
|
|
|
|
// validate the whole mapping and then throw errors together, so that user can get them after a single pipeline run
|
|
nodeIdExtDescriptorMapping, errGetNodeIdExtDescriptorMapping := formNodeIdExtDescriptorMappingWithValidation(utils, nodeNameExtDescriptorMapping, nodes, mtaYamlMap, mtaVersion)
|
|
if errGetNodeIdExtDescriptorMapping != nil {
|
|
log.SetErrorCategory(log.ErrorConfiguration)
|
|
return errGetNodeIdExtDescriptorMapping
|
|
}
|
|
|
|
for nodeId, mtaExtDescriptorPath := range nodeIdExtDescriptorMapping {
|
|
obtainedMtaExtDescriptor, errGetMtaExtDescriptor := communicationInstance.GetMtaExtDescriptor(nodeId, fmt.Sprintf("%v", mtaYamlMap["ID"]), mtaVersion)
|
|
if errGetMtaExtDescriptor != nil {
|
|
log.SetErrorCategory(log.ErrorService)
|
|
return fmt.Errorf("failed to get MTA extension descriptor: %w", errGetMtaExtDescriptor)
|
|
}
|
|
|
|
if obtainedMtaExtDescriptor != (tms.MtaExtDescriptor{}) {
|
|
_, errUpdateMtaExtDescriptor := communicationInstance.UpdateMtaExtDescriptor(nodeId, obtainedMtaExtDescriptor.Id, mtaExtDescriptorPath, mtaVersion, description, namedUser)
|
|
if errUpdateMtaExtDescriptor != nil {
|
|
log.SetErrorCategory(log.ErrorService)
|
|
return fmt.Errorf("failed to update MTA extension descriptor: %w", errUpdateMtaExtDescriptor)
|
|
}
|
|
} else {
|
|
_, errUploadMtaExtDescriptor := communicationInstance.UploadMtaExtDescriptorToNode(nodeId, mtaExtDescriptorPath, mtaVersion, description, namedUser)
|
|
if errUploadMtaExtDescriptor != nil {
|
|
log.SetErrorCategory(log.ErrorService)
|
|
return fmt.Errorf("failed to upload MTA extension descriptor to node: %w", errUploadMtaExtDescriptor)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fileInfo, errUploadFile := communicationInstance.UploadFile(mtaPath, namedUser)
|
|
if errUploadFile != nil {
|
|
log.SetErrorCategory(log.ErrorService)
|
|
return fmt.Errorf("failed to upload file: %w", errUploadFile)
|
|
}
|
|
|
|
_, errUploadFileToNode := communicationInstance.UploadFileToNode(nodeName, strconv.FormatInt(fileInfo.Id, 10), description, namedUser)
|
|
if errUploadFileToNode != nil {
|
|
log.SetErrorCategory(log.ErrorService)
|
|
return fmt.Errorf("failed to upload file to node: %w", errUploadFileToNode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func formNodeIdExtDescriptorMappingWithValidation(utils tmsUploadUtils, nodeNameExtDescriptorMapping map[string]interface{}, nodes []tms.Node, mtaYamlMap map[string]interface{}, mtaVersion string) (map[int64]string, error) {
|
|
var wrongMtaIdExtDescriptors []string
|
|
var wrongExtDescriptorPaths []string
|
|
var wrongNodeNames []string
|
|
var errorMessage string
|
|
|
|
nodeIdExtDescriptorMapping := make(map[int64]string)
|
|
for nodeName, mappedValue := range nodeNameExtDescriptorMapping {
|
|
mappedValueString := fmt.Sprintf("%v", mappedValue)
|
|
exists, _ := utils.FileExists(mappedValueString)
|
|
if exists {
|
|
extDescriptorMap, errGetYamlAsMap := getYamlAsMap(utils, mappedValueString)
|
|
if errGetYamlAsMap == nil {
|
|
if fmt.Sprintf("%v", mtaYamlMap["ID"]) != fmt.Sprintf("%v", extDescriptorMap["extends"]) {
|
|
wrongMtaIdExtDescriptors = append(wrongMtaIdExtDescriptors, mappedValueString)
|
|
}
|
|
} else {
|
|
wrappedErr := errors.Wrapf(errGetYamlAsMap, "tried to parse %v as yaml, but got an error", mappedValueString)
|
|
errorMessage += fmt.Sprintf("%v\n", wrappedErr)
|
|
}
|
|
} else {
|
|
wrongExtDescriptorPaths = append(wrongExtDescriptorPaths, mappedValueString)
|
|
}
|
|
|
|
isNodeFound := false
|
|
for _, node := range nodes {
|
|
if node.Name == nodeName {
|
|
nodeIdExtDescriptorMapping[node.Id] = mappedValueString
|
|
isNodeFound = true
|
|
break
|
|
}
|
|
}
|
|
if !isNodeFound {
|
|
wrongNodeNames = append(wrongNodeNames, nodeName)
|
|
}
|
|
}
|
|
|
|
if mtaVersion != "*" && mtaVersion != mtaYamlMap["version"] {
|
|
errorMessage += "parameter 'mtaVersion' does not match the MTA version in mta.yaml\n"
|
|
}
|
|
|
|
if len(wrongMtaIdExtDescriptors) > 0 || len(wrongExtDescriptorPaths) > 0 || len(wrongNodeNames) > 0 {
|
|
if len(wrongMtaIdExtDescriptors) > 0 {
|
|
sort.Strings(wrongMtaIdExtDescriptors)
|
|
errorMessage += fmt.Sprintf("parameter 'extends' in MTA extension descriptor files %v is not the same as MTA ID or is missing at all\n", wrongMtaIdExtDescriptors)
|
|
}
|
|
if len(wrongExtDescriptorPaths) > 0 {
|
|
sort.Strings(wrongExtDescriptorPaths)
|
|
errorMessage += fmt.Sprintf("MTA extension descriptor files %v do not exist\n", wrongExtDescriptorPaths)
|
|
}
|
|
if len(wrongNodeNames) > 0 {
|
|
sort.Strings(wrongNodeNames)
|
|
errorMessage += fmt.Sprintf("nodes %v do not exist. Please check node names provided in 'nodeExtDescriptorMapping' parameter or create these nodes\n", wrongNodeNames)
|
|
}
|
|
}
|
|
|
|
if errorMessage == "" {
|
|
return nodeIdExtDescriptorMapping, nil
|
|
} else {
|
|
return nil, errors.New(errorMessage)
|
|
}
|
|
}
|
|
|
|
func getYamlAsMap(utils tmsUploadUtils, yamlPath string) (map[string]interface{}, error) {
|
|
var result map[string]interface{}
|
|
bytes, err := utils.FileRead(yamlPath)
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
err = yaml.Unmarshal(bytes, &result)
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func unmarshalServiceKey(serviceKeyJson string) (serviceKey serviceKey, err error) {
|
|
err = json.Unmarshal([]byte(serviceKeyJson), &serviceKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|