diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 7e3d8a003a..8ef0ed8a79 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -70,7 +70,7 @@ you need to do the following in addition: * [Install Groovy](https://groovy-lang.org/install.html) * [Install Maven](https://maven.apache.org/install.html) -* Get a local Jenkins installed: Use for example [cx-server](https://github.com/SAP/devops-docker-cx-server) +* Get a local Jenkins installed ### Jenkins pipelines diff --git a/cmd/abapEnvironmentAssemblePackages_generated.go b/cmd/abapEnvironmentAssemblePackages_generated.go index 7eff152de7..256f85a79a 100644 --- a/cmd/abapEnvironmentAssemblePackages_generated.go +++ b/cmd/abapEnvironmentAssemblePackages_generated.go @@ -175,7 +175,7 @@ func addAbapEnvironmentAssemblePackagesFlags(cmd *cobra.Command, stepConfig *aba cmd.Flags().StringVar(&stepConfig.AddonDescriptor, "addonDescriptor", os.Getenv("PIPER_addonDescriptor"), "Structure in the commonPipelineEnvironment containing information about the Product Version and corresponding Software Component Versions") cmd.Flags().IntVar(&stepConfig.MaxRuntimeInMinutes, "maxRuntimeInMinutes", 360, "maximal runtime of the step in minutes") cmd.Flags().IntVar(&stepConfig.PollIntervalsInMilliseconds, "pollIntervalsInMilliseconds", 60000, "wait time in milliseconds till next status request in the backend system") - cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "certificates for the backend system, this certificates needs to be stored in .pipeline/trustStore") + cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore") cmd.MarkFlagRequired("username") cmd.MarkFlagRequired("password") diff --git a/cmd/abapEnvironmentBuild_generated.go b/cmd/abapEnvironmentBuild_generated.go index ad1fe3ed8b..ed84c605d4 100644 --- a/cmd/abapEnvironmentBuild_generated.go +++ b/cmd/abapEnvironmentBuild_generated.go @@ -197,7 +197,7 @@ func addAbapEnvironmentBuildFlags(cmd *cobra.Command, stepConfig *abapEnvironmen cmd.Flags().BoolVar(&stepConfig.TreatWarningsAsError, "treatWarningsAsError", false, "If a warrning occures, the step will be set to unstable") cmd.Flags().IntVar(&stepConfig.MaxRuntimeInMinutes, "maxRuntimeInMinutes", 360, "maximal runtime of the step in minutes") cmd.Flags().IntVar(&stepConfig.PollingIntervalInSeconds, "pollingIntervalInSeconds", 60, "wait time in seconds till next status request in the backend system") - cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "certificates for the backend system, this certificates needs to be stored in .pipeline/trustStore") + cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore") cmd.Flags().StringVar(&stepConfig.CpeValues, "cpeValues", os.Getenv("PIPER_cpeValues"), "Values taken from the previous step, if a value was also specified in the config file, the value from cpe will be discarded") cmd.Flags().StringVar(&stepConfig.UseFieldsOfAddonDescriptor, "useFieldsOfAddonDescriptor", os.Getenv("PIPER_useFieldsOfAddonDescriptor"), "use fields of the addonDescriptor in the cpe as input values. Please enter in the format '[{\"use\":\"Name\",\"renameTo\":\"SWC\"}]'") cmd.Flags().StringVar(&stepConfig.ConditionOnAddonDescriptor, "conditionOnAddonDescriptor", os.Getenv("PIPER_conditionOnAddonDescriptor"), "normally if useFieldsOfAddonDescriptor is not initial, a build is triggered for each repository in the addonDescriptor. This can be changed by posing conditions. Please enter in the format '[{\"field\":\"Status\",\"operator\":\"==\",\"value\":\"P\"}]'") diff --git a/cmd/abapEnvironmentCheckoutBranch.go b/cmd/abapEnvironmentCheckoutBranch.go index a1c7bd9642..684b03a2da 100644 --- a/cmd/abapEnvironmentCheckoutBranch.go +++ b/cmd/abapEnvironmentCheckoutBranch.go @@ -47,6 +47,7 @@ func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOpti if errorGetInfo != nil { log.Entry().WithError(errorGetInfo).Fatal("Parameters for the ABAP Connection not available") } + connectionDetails.CertificateNames = options.CertificateNames repositories := []abaputils.Repository{} err = checkCheckoutBranchRepositoryConfiguration(*options) diff --git a/cmd/abapEnvironmentCheckoutBranch_generated.go b/cmd/abapEnvironmentCheckoutBranch_generated.go index 89e3d5e849..988ebfc9d4 100644 --- a/cmd/abapEnvironmentCheckoutBranch_generated.go +++ b/cmd/abapEnvironmentCheckoutBranch_generated.go @@ -16,17 +16,18 @@ import ( ) type abapEnvironmentCheckoutBranchOptions struct { - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - RepositoryName string `json:"repositoryName,omitempty"` - BranchName string `json:"branchName,omitempty"` - Host string `json:"host,omitempty"` - Repositories string `json:"repositories,omitempty"` - CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"` - CfOrg string `json:"cfOrg,omitempty"` - CfSpace string `json:"cfSpace,omitempty"` - CfServiceInstance string `json:"cfServiceInstance,omitempty"` - CfServiceKeyName string `json:"cfServiceKeyName,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + RepositoryName string `json:"repositoryName,omitempty"` + BranchName string `json:"branchName,omitempty"` + Host string `json:"host,omitempty"` + Repositories string `json:"repositories,omitempty"` + CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"` + CfOrg string `json:"cfOrg,omitempty"` + CfSpace string `json:"cfSpace,omitempty"` + CfServiceInstance string `json:"cfServiceInstance,omitempty"` + CfServiceKeyName string `json:"cfServiceKeyName,omitempty"` + CertificateNames []string `json:"certificateNames,omitempty"` } // AbapEnvironmentCheckoutBranchCommand Switches between branches of a git repository on a SAP BTP ABAP Environment system @@ -146,6 +147,7 @@ func addAbapEnvironmentCheckoutBranchFlags(cmd *cobra.Command, stepConfig *abapE cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space") cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") + cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore") cmd.MarkFlagRequired("username") cmd.MarkFlagRequired("password") @@ -276,6 +278,15 @@ func abapEnvironmentCheckoutBranchMetadata() config.StepData { Aliases: []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKeyName"}}, Default: os.Getenv("PIPER_cfServiceKeyName"), }, + { + Name: "certificateNames", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: []string{}, + }, }, }, Containers: []config.Container{ diff --git a/cmd/abapEnvironmentCloneGitRepo.go b/cmd/abapEnvironmentCloneGitRepo.go index 9776312b2e..687044dd77 100644 --- a/cmd/abapEnvironmentCloneGitRepo.go +++ b/cmd/abapEnvironmentCloneGitRepo.go @@ -52,6 +52,7 @@ func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions, if errorGetInfo != nil { return errors.Wrap(errorGetInfo, "Parameters for the ABAP Connection not available") } + connectionDetails.CertificateNames = config.CertificateNames log.Entry().Infof("Start cloning %v repositories", len(repositories)) for _, repo := range repositories { diff --git a/cmd/abapEnvironmentCloneGitRepo_generated.go b/cmd/abapEnvironmentCloneGitRepo_generated.go index d60b2ff76b..9cba6305e5 100644 --- a/cmd/abapEnvironmentCloneGitRepo_generated.go +++ b/cmd/abapEnvironmentCloneGitRepo_generated.go @@ -16,17 +16,18 @@ import ( ) type abapEnvironmentCloneGitRepoOptions struct { - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - Repositories string `json:"repositories,omitempty"` - RepositoryName string `json:"repositoryName,omitempty"` - BranchName string `json:"branchName,omitempty"` - Host string `json:"host,omitempty"` - CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"` - CfOrg string `json:"cfOrg,omitempty"` - CfSpace string `json:"cfSpace,omitempty"` - CfServiceInstance string `json:"cfServiceInstance,omitempty"` - CfServiceKeyName string `json:"cfServiceKeyName,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Repositories string `json:"repositories,omitempty"` + RepositoryName string `json:"repositoryName,omitempty"` + BranchName string `json:"branchName,omitempty"` + Host string `json:"host,omitempty"` + CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"` + CfOrg string `json:"cfOrg,omitempty"` + CfSpace string `json:"cfSpace,omitempty"` + CfServiceInstance string `json:"cfServiceInstance,omitempty"` + CfServiceKeyName string `json:"cfServiceKeyName,omitempty"` + CertificateNames []string `json:"certificateNames,omitempty"` } // AbapEnvironmentCloneGitRepoCommand Clones a git repository to a SAP BTP ABAP Environment system @@ -146,6 +147,7 @@ func addAbapEnvironmentCloneGitRepoFlags(cmd *cobra.Command, stepConfig *abapEnv cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space") cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") + cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore") cmd.MarkFlagRequired("username") cmd.MarkFlagRequired("password") @@ -276,6 +278,15 @@ func abapEnvironmentCloneGitRepoMetadata() config.StepData { Aliases: []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKey"}}, Default: os.Getenv("PIPER_cfServiceKeyName"), }, + { + Name: "certificateNames", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: []string{}, + }, }, }, Containers: []config.Container{ diff --git a/cmd/abapEnvironmentCreateTag.go b/cmd/abapEnvironmentCreateTag.go index 961b062f42..5adebcda7d 100644 --- a/cmd/abapEnvironmentCreateTag.go +++ b/cmd/abapEnvironmentCreateTag.go @@ -40,6 +40,7 @@ func runAbapEnvironmentCreateTag(config *abapEnvironmentCreateTagOptions, com ab if errorGetInfo != nil { return errors.Wrap(errorGetInfo, "Parameters for the ABAP Connection not available") } + connectionDetails.CertificateNames = config.CertificateNames backlog, errorPrepare := prepareBacklog(config) if errorPrepare != nil { diff --git a/cmd/abapEnvironmentCreateTag_generated.go b/cmd/abapEnvironmentCreateTag_generated.go index 2039810749..02b47ef577 100644 --- a/cmd/abapEnvironmentCreateTag_generated.go +++ b/cmd/abapEnvironmentCreateTag_generated.go @@ -16,21 +16,22 @@ import ( ) type abapEnvironmentCreateTagOptions struct { - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - Repositories string `json:"repositories,omitempty"` - RepositoryName string `json:"repositoryName,omitempty"` - CommitID string `json:"commitID,omitempty"` - TagName string `json:"tagName,omitempty"` - TagDescription string `json:"tagDescription,omitempty"` - GenerateTagForAddonProductVersion bool `json:"generateTagForAddonProductVersion,omitempty"` - GenerateTagForAddonComponentVersion bool `json:"generateTagForAddonComponentVersion,omitempty"` - Host string `json:"host,omitempty"` - CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"` - CfOrg string `json:"cfOrg,omitempty"` - CfSpace string `json:"cfSpace,omitempty"` - CfServiceInstance string `json:"cfServiceInstance,omitempty"` - CfServiceKeyName string `json:"cfServiceKeyName,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Repositories string `json:"repositories,omitempty"` + RepositoryName string `json:"repositoryName,omitempty"` + CommitID string `json:"commitID,omitempty"` + TagName string `json:"tagName,omitempty"` + TagDescription string `json:"tagDescription,omitempty"` + GenerateTagForAddonProductVersion bool `json:"generateTagForAddonProductVersion,omitempty"` + GenerateTagForAddonComponentVersion bool `json:"generateTagForAddonComponentVersion,omitempty"` + Host string `json:"host,omitempty"` + CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"` + CfOrg string `json:"cfOrg,omitempty"` + CfSpace string `json:"cfSpace,omitempty"` + CfServiceInstance string `json:"cfServiceInstance,omitempty"` + CfServiceKeyName string `json:"cfServiceKeyName,omitempty"` + CertificateNames []string `json:"certificateNames,omitempty"` } // AbapEnvironmentCreateTagCommand Creates a tag for a git repository to a SAP BTP ABAP Environment system @@ -154,6 +155,7 @@ func addAbapEnvironmentCreateTagFlags(cmd *cobra.Command, stepConfig *abapEnviro cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space") cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") + cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore") cmd.MarkFlagRequired("username") cmd.MarkFlagRequired("password") @@ -320,6 +322,15 @@ func abapEnvironmentCreateTagMetadata() config.StepData { Aliases: []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKey"}}, Default: os.Getenv("PIPER_cfServiceKeyName"), }, + { + Name: "certificateNames", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: []string{}, + }, }, }, Containers: []config.Container{ diff --git a/cmd/abapEnvironmentPullGitRepo.go b/cmd/abapEnvironmentPullGitRepo.go index 8c93a2d55c..93e51a3048 100644 --- a/cmd/abapEnvironmentPullGitRepo.go +++ b/cmd/abapEnvironmentPullGitRepo.go @@ -45,6 +45,7 @@ func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, c if err != nil { return errors.Wrap(err, "Parameters for the ABAP Connection not available") } + connectionDetails.CertificateNames = options.CertificateNames var repositories []abaputils.Repository err = checkPullRepositoryConfiguration(*options) diff --git a/cmd/abapEnvironmentPullGitRepo_generated.go b/cmd/abapEnvironmentPullGitRepo_generated.go index 4648870120..3575ef4fb2 100644 --- a/cmd/abapEnvironmentPullGitRepo_generated.go +++ b/cmd/abapEnvironmentPullGitRepo_generated.go @@ -29,6 +29,7 @@ type abapEnvironmentPullGitRepoOptions struct { CfServiceInstance string `json:"cfServiceInstance,omitempty"` CfServiceKeyName string `json:"cfServiceKeyName,omitempty"` IgnoreCommit bool `json:"ignoreCommit,omitempty"` + CertificateNames []string `json:"certificateNames,omitempty"` } // AbapEnvironmentPullGitRepoCommand Pulls a git repository to a SAP BTP ABAP Environment system @@ -150,6 +151,7 @@ func addAbapEnvironmentPullGitRepoFlags(cmd *cobra.Command, stepConfig *abapEnvi cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") cmd.Flags().BoolVar(&stepConfig.IgnoreCommit, "ignoreCommit", false, "ingores a commit provided via the repositories file") + cmd.Flags().StringSliceVar(&stepConfig.CertificateNames, "certificateNames", []string{}, "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore") cmd.MarkFlagRequired("username") cmd.MarkFlagRequired("password") @@ -298,6 +300,15 @@ func abapEnvironmentPullGitRepoMetadata() config.StepData { Aliases: []config.Alias{}, Default: false, }, + { + Name: "certificateNames", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: []string{}, + }, }, }, Containers: []config.Container{ diff --git a/documentation/docs/guidedtour.md b/documentation/docs/guidedtour.md index ff8c53573f..71fdbf472b 100644 --- a/documentation/docs/guidedtour.md +++ b/documentation/docs/guidedtour.md @@ -50,7 +50,7 @@ Copy the sources of the application into your own Git repository. While we will 1. Save your changes to your remote repository. -1. To set up a Jenkins job for your repository, open the Jenkins UI under `http://:` and choose **New Item**. Per default, the `cx-server` starts Jenkins on HTTP port `80`. For more information, see the [Jenkins User Documentation][jenkins-io-documentation]. +1. To set up a Jenkins job for your repository, open the Jenkins UI under `http://:` and choose **New Item**. For more information, see the [Jenkins User Documentation][jenkins-io-documentation]. ![Clicke New Item](images/JenkinsHomeMenu-1.png "Jenkins Home Menu") diff --git a/documentation/docs/infrastructure/customjenkins.md b/documentation/docs/infrastructure/customjenkins.md index 29d33db9a9..54e8ea0c40 100644 --- a/documentation/docs/infrastructure/customjenkins.md +++ b/documentation/docs/infrastructure/customjenkins.md @@ -24,18 +24,6 @@ docker run ... -v /var/run/docker.sock:/var/run/docker.sock ... Project "Piper" requires a set of plugins installed on your Jenkins server. This set may evolve in the future. Make sure that all plugins of the appropriate versions are installed. -The Cx server repository contains an [up-to-date list][devops-cxs-plugins] of the required plugins. To ease the installation, download the list with the following command and use the [Jenkins client][jenkins-doc-client]: - -``` -curl -o plugins.txt https://raw.githubusercontent.com/SAP/devops-docker-cx-server/master/jenkins-master/plugins.txt -``` - -On the Jenkins server, run the following command with a user that has administration rights: - -``` -cat plugins.txt | awk '{system("java " "-jar jenkins-cli.jar -s http://localhost:8080 -auth ${ADM_USER}:${ADM_PASSWD} install-plugin " $1)}' -``` - ## Shared Library Shared libraries extending the Jenkins pipeline are defined within the Jenkins system configuration. A library is defined by a link to its source repository and an appropriate version identifier. To add the project "Piper"s library, execute the following steps: @@ -100,7 +88,5 @@ If you face such a [user permission issue][piper-issue-781], choose between the [docker-install]: https://docs.docker.com/install [dockerhub-node]: https://hub.docker.com/_/node/ [docker-getstarted]: https://docs.docker.com/get-started/ -[jenkins-doc-client]: https://jenkins.io/doc/book/managing/cli/ [jenkins-docker-image]: https://github.com/jenkinsci/docker/ [piper-issue-781]: https://github.com/SAP/jenkins-library/issues/781 -[devops-cxs-plugins]: https://github.com/SAP/devops-docker-cx-server/blob/master/jenkins-master/plugins.txt diff --git a/documentation/docs/infrastructure/overview.md b/documentation/docs/infrastructure/overview.md index aaf4451044..8fae679b6b 100644 --- a/documentation/docs/infrastructure/overview.md +++ b/documentation/docs/infrastructure/overview.md @@ -1,128 +1,7 @@ # Infrastructure -Besides SAP specific Jenkins library steps and out-of-the-box pipelines, project "Piper" offers also documentation and tooling to start the corresponding Jenkins server with all the configuration required to run project "Piper" pipelines. - -The core of the Jenkins infrastructure tooling is a set of [Docker images][docker-images]. -There is a main Docker image containing a preconfigured Jenkins and several tooling images used in the specific project "Piper" steps. - -!!! info "Docker Hub rate limiting" - Please be aware that Docker Hub as rate limiting active which might cause project "Piper" pipelines to fail. - Refer to the [page dedicated to docker rate limiting for details and solutions][resources-docker-rate-limit]. - -The document and the linked resources explain the various ways of starting such a Jenkins server based on these Docker images. - -## Cx Server (Recommended) - -Cx Server is a life-cycle management tool to bootstrap a pre-configured Jenkins instance within minutes on your own (virtual) server. -It uses the Docker images mentioned above. -As it would be cumbersome to start the Docker image manually with all required parameters and sidecar images, this command line tool automates the bootstraping. - -### Setting up a Jenkins master - -For the following steps you will need a server or another machine which has Docker installed and configured. - -To get started, initialize the Cx Server by using this `docker run` command: - -```sh -docker run -it --rm -u $(id -u):$(id -g) -v "${PWD}":/cx-server/mount/ ppiper/cx-server-companion:latest init-cx-server -``` - -This creates a few files in your current working directory. -The shell script `cx-server` and the configuration file `server.cfg` are of special interest. - -Now, you can start the Jenkins server by using the following command: - -```sh -chmod +x ./cx-server -./cx-server start -``` - -For more information on the Cx Server and how to customize your Jenkins, have a look at the [Operations Guide for Cx Server][devops-docker-images-cxs-guide]. - -### Setting up Jenkins agents - -With more and more qualities checked automatically in the pipeline, more and more resources are required to handle the workload. -This section shows how to scale the pipeline by adding [Jenkins build agents][build-agents]. - -However, before setting up agents please consider also other ways to scale the build infrastructure. -It might be an option to have only one Jenkins master with lots of resources (cpu cores, memory) per project or team. -This has the advantage of bringing more configuration flexibility and isolation for the individual teams but has the disadvantage that parts of the configuration have to be maintained twice. -Furthermore, having agents and thus network communication between the build servers increases the risk of failures. - -To add an agent to the Jenkins master, please make sure to fulfil the following requirements similar to the ones for the Jenkins master: - -- Access to a new server which runs on Linux -- Docker installed on this server - -The connection between the master and the agents will be established via ssh. -As the Jenkins master runs in a Docker container, the ssh setup steps, such as creating and storing a private/public key pair or maintaining the konwn hosts file has to be done inside this container. - -To execute these steps inside the container, execute the following command on the server where the Jenkins master is running: - -```bash -docker exec -it cx-jenkins-master bash -``` - -Inside the container make sure to be able to access the server where the Jenkins agent should be started by running the following command. As user you should use a user which is able to execute `docker` commands, i.e. starting a docker container. - -```bash -ssh @ -``` - -To be able to access the agent via ssh with the command above you might need to generate a new ssh key with `ssh-keygen`, store it in the `.ssh` folder and register the public key on the agent server. -You might also need to add server’s fingerprint to the list of known hosts. -For more information around establishing a ssh connection please consult the [ssh documentation][ssh-documentation]. - -To setup a new Jenkins agent, open "Manage Jenkins" > "Manage Nodes" > "New Nodes" and create a new "Permanent Agent" - -Please define `/var/jenkins_home` as "Remote root directory". -The launch method has to be "Launch agent via execution of command on the master" and the command should be: -`./var/jenkins_home/launch-jenkins-agent.sh [image]`. -User and host should equal the values you used above to test the ssh connection. - -The following picture shows an example configuration. - -![Agent Setup](../images/agent.png "Agent Setup") - -## Kubernetes (Experimental) - -Hosting Jenkins master and agents means that we bind the required resources to the purpose of executing builds. -There are good chances that, these resources stay idle for the most part of the day, i.e. if you have high peak loads. -Autoscaling of the infrastructure solves such a problem. -Instead of reserving the resources proactively, the pipeline creates the Jenkins agents dynamically on a Kubernetes cluster during the execution. -Once the agent completes the dedicated task, it is deleted and the resources are freed. -Project "Piper" supports running the pipeline as well as individual steps in a Kubernetes Cluster. -Please note that this feature is currently only experimental. - -To setup the Jenkins master in Kubernetes you can use helm. -The documentation to install Jenkins using helm can be found [here][jenkins-helm]. - -To use the Jenkins image provided by project Piper, pass `ppiper/jenkins-master` as a value for the `Master.Image` command line argument while deploying Jenkins to Kubernetes. - -The successfully completed deployment consists of a Jenkins pod with port 80 and 50000 exposed for HTTP and internal JNLP traffic respectively. -The deployment also creates two services each to listen to incoming HTTP traffic on port 80 and the internal JNLP traffic on port 50000. -Please note that in this example setup, the SSL/TLS termination happens at the load balancer, hence all the traffic between a load balancer and the Jenkins pod is unencrypted. - -Project "Piper" needs an environment variable set in the Jenkins to run the workload in Kubernetes. -In order to set the environment variable, navigate to "Manage Jenkins" > "Configure System" > "Global Properties". -Add an environment variable ON_K8S and set the value to true: - -![Environment Variable ON_K8S](../images/env.png "Environment Variable ON_K8S") - -Afterwards, you should be able to run project "Piper" pipelines in Kubernetes. - ## Custom Jenkins -### On your own: Custom Jenkins Setup - -If you use your own Jenkins installation, you need to care for the configuration that is specific to project "Piper". -This option should only be considered if you know why you need it, otherwise using the Cx Server life-cycle management makes your life much easier. -If you choose to go this path, follow the [Custom Jenkins Setup guide][resources-custom-jenkins]. +To run project "Piper", you will need your own Jenkins installation, and you need to care for the configuration that is specific to project "Piper". Please follow the [Custom Jenkins Setup guide][resources-custom-jenkins]. -[devops-docker-images-cxs-guide]: https://github.com/SAP/devops-docker-cx-server/blob/master/docs/operations/cx-server-operations-guide.md -[docker-images]: https://hub.docker.com/u/ppiper -[resources-docker-rate-limit]: docker-rate-limit.md [resources-custom-jenkins]: customjenkins.md -[build-agents]: https://wiki.jenkins.io/display/jenkins/distributed+builds -[ssh-documentation]: https://www.openssh.com/manual.html -[jenkins-helm]: https://github.com/helm/charts/tree/master/stable/jenkins diff --git a/documentation/docs/scenarios/abapEnvironmentAddons.md b/documentation/docs/scenarios/abapEnvironmentAddons.md index 1baf903bd5..eddfed2137 100644 --- a/documentation/docs/scenarios/abapEnvironmentAddons.md +++ b/documentation/docs/scenarios/abapEnvironmentAddons.md @@ -107,7 +107,7 @@ There are several prerequisites to run the pipeline for building an ABAP Enviro #### Jenkins Server -The pipeline responsible for building ABAP add-ons has been created specifically for [Jenkins](https://www.jenkins.io). Therefore, a Jenkins Server is required. The [piper project](https://sap.github.io/jenkins-library/guidedtour/) provides with [Cx Server](https://www.project-piper.io/infrastructure/overview/#cx-server-recommended) a life-cycle management tool to bootstrap a pre-configured Jenkins instance, which already includes the necessary configuration. Of course, it is also possible to [configure an existing server](https://sap.github.io/jenkins-library/infrastructure/customjenkins/). +The pipeline responsible for building ABAP add-ons has been created specifically for [Jenkins](https://www.jenkins.io). Therefore, a Jenkins Server is required. Please follow these instructions to [configure an existing server](https://sap.github.io/jenkins-library/infrastructure/customjenkins/). #### Git Repository diff --git a/documentation/docs/scenarios/gCTS_Scenario.md b/documentation/docs/scenarios/gCTS_Scenario.md index 1f957bc45e..394d990494 100644 --- a/documentation/docs/scenarios/gCTS_Scenario.md +++ b/documentation/docs/scenarios/gCTS_Scenario.md @@ -23,7 +23,7 @@ This scenario explains how to use a pipeline to deploy a commit to a test system - You have at least two ABAP systems with a version SAP S/4HANA 2020 or higher. You need one development system that you use to push objects to the Git repository, and a test system on which you run the pipeline. You have created and cloned the Git repository on all systems, on the development system with the *Development* role, and on the others with the *Provided* role. - You have enabled [ATC](https://help.sap.com/docs/ABAP_PLATFORM_NEW/ba879a6e2ea04d9bb94c7ccd7cdac446/62c41ad841554516bb06fb3620540e47.html) checks in transaction ATC in the test system. - You have access to a Jenkins instance including the [Warnings-Next-Generation Plugin](https://plugins.jenkins.io/warnings-ng/). The plug-in must be installed separately. It is required to view the results of the testing after the pipeline has run. - For the gCTS scenario, we recommend that you use the [Custom Jenkins setup](https://www.project-piper.io/infrastructure/customjenkins/) even though it is possible to run the gCTS scenario with [Piper´s CX server](https://www.project-piper.io/infrastructure/overview/). + For the gCTS scenario, we recommend that you use the [Custom Jenkins setup](https://www.project-piper.io/infrastructure/customjenkins/). - You have set up a suitable Jenkins instance as described under [Getting Started with Project "Piper"](https://www.project-piper.io/guidedtour/) under *Create Your First Pipeline*. - The user that is used for the execution of the pipeline must have the credentials entered in gCTS as described in the gCTS documentation under [Set User-Specific Authentication](https://help.sap.com/docs/ABAP_PLATFORM_NEW/4a368c163b08418890a406d413933ba7/3431ebd6fbf241778cd60587e7b5dc3e.html). diff --git a/pkg/abaputils/abaputils.go b/pkg/abaputils/abaputils.go index 9b944cdc31..6f3d20bf35 100644 --- a/pkg/abaputils/abaputils.go +++ b/pkg/abaputils/abaputils.go @@ -9,7 +9,6 @@ import ( "os" "path/filepath" "regexp" - "strconv" "strings" "time" @@ -244,17 +243,6 @@ func GetErrorDetailsFromResponse(resp *http.Response) (errorString string, error } -// ConvertTime formats an ABAP timestamp string from format /Date(1585576807000+0000)/ into a UNIX timestamp and returns it -func ConvertTime(logTimeStamp string) time.Time { - seconds := strings.TrimPrefix(strings.TrimSuffix(logTimeStamp, "000+0000)/"), "/Date(") - n, error := strconv.ParseInt(seconds, 10, 64) - if error != nil { - return time.Unix(0, 0).UTC() - } - t := time.Unix(n, 0).UTC() - return t -} - // AddDefaultDashedLine adds 25 dashes func AddDefaultDashedLine(j int) { for i := 1; i <= j; i++ { @@ -312,11 +300,12 @@ type AbapMetadata struct { // ConnectionDetailsHTTP contains fields for HTTP connections including the XCSRF token type ConnectionDetailsHTTP struct { - Host string - User string `json:"user"` - Password string `json:"password"` - URL string `json:"url"` - XCsrfToken string `json:"xcsrftoken"` + Host string + User string `json:"user"` + Password string `json:"password"` + URL string `json:"url"` + XCsrfToken string `json:"xcsrftoken"` + CertificateNames []string `json:"-"` } // AbapError contains the error code and the error message for ABAP errors diff --git a/pkg/abaputils/abaputils_test.go b/pkg/abaputils/abaputils_test.go index 8bfc272f93..56688f7aec 100644 --- a/pkg/abaputils/abaputils_test.go +++ b/pkg/abaputils/abaputils_test.go @@ -271,27 +271,6 @@ func TestReadServiceKeyAbapEnvironment(t *testing.T) { }) } -func TestTimeConverter(t *testing.T) { - t.Run("Test example time", func(t *testing.T) { - inputDate := "/Date(1585576809000+0000)/" - expectedDate := "2020-03-30 14:00:09 +0000 UTC" - result := ConvertTime(inputDate) - assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") - }) - t.Run("Test Unix time", func(t *testing.T) { - inputDate := "/Date(0000000000000+0000)/" - expectedDate := "1970-01-01 00:00:00 +0000 UTC" - result := ConvertTime(inputDate) - assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") - }) - t.Run("Test unexpected format", func(t *testing.T) { - inputDate := "/Date(0012300000001+0000)/" - expectedDate := "1970-01-01 00:00:00 +0000 UTC" - result := ConvertTime(inputDate) - assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") - }) -} - func TestHandleHTTPError(t *testing.T) { t.Run("Test", func(t *testing.T) { diff --git a/pkg/abaputils/manageGitRepositoryUtils.go b/pkg/abaputils/manageGitRepositoryUtils.go index 7d6b8224de..d53755a50e 100644 --- a/pkg/abaputils/manageGitRepositoryUtils.go +++ b/pkg/abaputils/manageGitRepositoryUtils.go @@ -58,7 +58,7 @@ func PrintLogs(api SoftwareComponentApiInterface) { return results[i].Index < results[j].Index }) - printOverview(results) + printOverview(results, api) // Print Details for _, logEntryForDetails := range results { @@ -80,7 +80,7 @@ func printExecutionLogs(executionLogs ExecutionLog) { AddDefaultDashedLine(1) } -func printOverview(results []LogResultsV2) { +func printOverview(results []LogResultsV2, api SoftwareComponentApiInterface) { logOutputPhaseLength, logOutputLineLength := calculateLenghts(results) @@ -93,7 +93,7 @@ func printOverview(results []LogResultsV2) { printDashedLine(logOutputLineLength) for _, logEntry := range results { - log.Entry().Infof("| %-"+fmt.Sprint(logOutputPhaseLength)+"s | %"+fmt.Sprint(logOutputStatusLength)+"s | %-"+fmt.Sprint(logOutputTimestampLength)+"s |", logEntry.Name, logEntry.Status, ConvertTime(logEntry.Timestamp)) + log.Entry().Infof("| %-"+fmt.Sprint(logOutputPhaseLength)+"s | %"+fmt.Sprint(logOutputStatusLength)+"s | %-"+fmt.Sprint(logOutputTimestampLength)+"s |", logEntry.Name, logEntry.Status, api.ConvertTime(logEntry.Timestamp)) } printDashedLine(logOutputLineLength) } @@ -117,7 +117,7 @@ func printDashedLine(i int) { func printLog(logOverviewEntry LogResultsV2, api SoftwareComponentApiInterface) { page := 0 - printHeader(logOverviewEntry) + printHeader(logOverviewEntry, api) for { logProtocols, count, err := api.GetLogProtocol(logOverviewEntry, page) printLogProtocolEntries(logOverviewEntry, logProtocols) @@ -149,16 +149,16 @@ func allLogsHaveBeenPrinted(protocols []LogProtocol, page int, count int, err er return (err != nil || allPagesHaveBeenRead || reflect.DeepEqual(protocols, []LogProtocol{})) } -func printHeader(logEntry LogResultsV2) { - if logEntry.Status != `Success` { +func printHeader(logEntry LogResultsV2, api SoftwareComponentApiInterface) { + if logEntry.Status == `Error` { log.Entry().Infof("\n") AddDefaultDashedLine(1) - log.Entry().Infof("%s (%v)", logEntry.Name, ConvertTime(logEntry.Timestamp)) + log.Entry().Infof("%s (%v)", logEntry.Name, api.ConvertTime(logEntry.Timestamp)) AddDefaultDashedLine(1) } else { log.Entry().Debugf("\n") AddDebugDashedLine() - log.Entry().Debugf("%s (%v)", logEntry.Name, ConvertTime(logEntry.Timestamp)) + log.Entry().Debugf("%s (%v)", logEntry.Name, api.ConvertTime(logEntry.Timestamp)) AddDebugDashedLine() } } diff --git a/pkg/abaputils/sap_com_0510.go b/pkg/abaputils/sap_com_0510.go index b330224f66..f543c9ff6f 100644 --- a/pkg/abaputils/sap_com_0510.go +++ b/pkg/abaputils/sap_com_0510.go @@ -330,6 +330,7 @@ func (api *SAP_COM_0510) initialRequest() error { CookieJar: cookieJar, Username: api.con.User, Password: api.con.Password, + TrustedCerts: api.con.CertificateNames, }) headConnection := api.con @@ -387,3 +388,14 @@ func (api *SAP_COM_0510) getLogProtocolQuery(page int) string { return fmt.Sprintf("?$skip=%s&$top=%s&$inlinecount=allpages", fmt.Sprint(skip), fmt.Sprint(top)) } + +// ConvertTime formats an ABAP timestamp string from format /Date(1585576807000+0000)/ into a UNIX timestamp and returns it +func (api *SAP_COM_0510) ConvertTime(logTimeStamp string) time.Time { + seconds := strings.TrimPrefix(strings.TrimSuffix(logTimeStamp, "000+0000)/"), "/Date(") + n, error := strconv.ParseInt(seconds, 10, 64) + if error != nil { + return time.Unix(0, 0).UTC() + } + t := time.Unix(n, 0).UTC() + return t +} diff --git a/pkg/abaputils/sap_com_0510_test.go b/pkg/abaputils/sap_com_0510_test.go index 776aa28d7f..28c3af01e6 100644 --- a/pkg/abaputils/sap_com_0510_test.go +++ b/pkg/abaputils/sap_com_0510_test.go @@ -481,3 +481,27 @@ func TestSleepTime(t *testing.T) { assert.ErrorContains(t, err, "Exceeded max sleep time") }) } + +func TestTimeConverter(t *testing.T) { + + api := SAP_COM_0510{} + + t.Run("Test example time", func(t *testing.T) { + inputDate := "/Date(1585576809000+0000)/" + expectedDate := "2020-03-30 14:00:09 +0000 UTC" + result := api.ConvertTime(inputDate) + assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") + }) + t.Run("Test Unix time", func(t *testing.T) { + inputDate := "/Date(0000000000000+0000)/" + expectedDate := "1970-01-01 00:00:00 +0000 UTC" + result := api.ConvertTime(inputDate) + assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") + }) + t.Run("Test unexpected format", func(t *testing.T) { + inputDate := "/Date(0012300000001+0000)/" + expectedDate := "1970-01-01 00:00:00 +0000 UTC" + result := api.ConvertTime(inputDate) + assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") + }) +} diff --git a/pkg/abaputils/sap_com_0948.go b/pkg/abaputils/sap_com_0948.go index f6b7be68b5..de1ac13eba 100644 --- a/pkg/abaputils/sap_com_0948.go +++ b/pkg/abaputils/sap_com_0948.go @@ -339,6 +339,7 @@ func (api *SAP_COM_0948) initialRequest() error { CookieJar: cookieJar, Username: api.con.User, Password: api.con.Password, + TrustedCerts: api.con.CertificateNames, }) // HEAD request to the root is not sufficient, as an unauthorized called is allowed to do so @@ -406,3 +407,12 @@ func (api *SAP_COM_0948) getLogProtocolQuery(page int) string { return fmt.Sprintf("?$skip=%s&$top=%s&$count=true", fmt.Sprint(skip), fmt.Sprint(top)) } + +// ConvertTime formats an ISO 8601 timestamp string from format 2024-05-02T09:25:40Z into a UNIX timestamp and returns it +func (api *SAP_COM_0948) ConvertTime(logTimeStamp string) time.Time { + t, error := time.Parse(time.RFC3339, logTimeStamp) + if error != nil { + return time.Unix(0, 0).UTC() + } + return t +} diff --git a/pkg/abaputils/sap_com_0948_test.go b/pkg/abaputils/sap_com_0948_test.go index 24f7e6702c..8855e994ef 100644 --- a/pkg/abaputils/sap_com_0948_test.go +++ b/pkg/abaputils/sap_com_0948_test.go @@ -482,6 +482,30 @@ func TestSleepTime0948(t *testing.T) { }) } +func TestTimeConverter0948(t *testing.T) { + + api := SAP_COM_0948{} + + t.Run("Test example time", func(t *testing.T) { + inputDate := "2024-05-02T09:25:40Z" + expectedDate := "2024-05-02 09:25:40 +0000 UTC" + result := api.ConvertTime(inputDate) + assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") + }) + t.Run("Test Unix time", func(t *testing.T) { + inputDate := "2023-12-24T16:19:29.000Z" + expectedDate := "2023-12-24 16:19:29 +0000 UTC" + result := api.ConvertTime(inputDate) + assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") + }) + t.Run("Test unexpected format", func(t *testing.T) { + inputDate := "2024-05-02T09:254:40Z" + expectedDate := "1970-01-01 00:00:00 +0000 UTC" + result := api.ConvertTime(inputDate) + assert.Equal(t, expectedDate, result.String(), "Dates do not match after conversion") + }) +} + func TestGetExecutionLog(t *testing.T) { t.Run("Test Get Executionlog Success", func(t *testing.T) { diff --git a/pkg/abaputils/softwareComponentApiManager.go b/pkg/abaputils/softwareComponentApiManager.go index 813df3c3ef..c4d02e7115 100644 --- a/pkg/abaputils/softwareComponentApiManager.go +++ b/pkg/abaputils/softwareComponentApiManager.go @@ -67,6 +67,7 @@ type SoftwareComponentApiInterface interface { CreateTag(tag Tag) error GetLogOverview() ([]LogResultsV2, error) GetLogProtocol(LogResultsV2, int) (result []LogProtocol, count int, err error) + ConvertTime(logTimeStamp string) time.Time GetExecutionLog() (ExecutionLog, error) } diff --git a/pkg/config/config.go b/pkg/config/config.go index 14f65686a8..65803ec296 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -510,7 +510,17 @@ func merge(base, overlay map[string]interface{}, metadata StepData) map[string]i for _, v := range metadata.Spec.Inputs.Parameters { tVal := reflect.TypeOf(value).String() if v.Name == key && tVal != v.Type { - log.Entry().Warn("config value provided for ", v.Name, " is of wrong type ", tVal, " should be of type ", v.Type) + if tVal == "[]interface {}" && v.Type == "[]string" { + //json Unmarshal genertes arrays of interface{} for string arrays + for _, interfaceValue := range value.([]interface{}) { + arrayValueType := reflect.TypeOf(interfaceValue).String() + if arrayValueType != "string" { + log.Entry().Warnf("config id %s should only contain strings but contains a %s", v.Name, arrayValueType) + } + } + } else { + log.Entry().Warnf("config value provided for %s is of wrong type %s should be of type %s", v.Name, tVal, v.Type) + } } } } diff --git a/resources/metadata/abapEnvironmentAssemblePackages.yaml b/resources/metadata/abapEnvironmentAssemblePackages.yaml index 9ef2c70de2..d252d8e193 100644 --- a/resources/metadata/abapEnvironmentAssemblePackages.yaml +++ b/resources/metadata/abapEnvironmentAssemblePackages.yaml @@ -129,7 +129,7 @@ spec: - STEPS - name: certificateNames type: "[]string" - description: certificates for the backend system, this certificates needs to be stored in .pipeline/trustStore + description: "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore" mandatory: false scope: - PARAMETERS diff --git a/resources/metadata/abapEnvironmentBuild.yaml b/resources/metadata/abapEnvironmentBuild.yaml index b67b372671..3aee96ae9e 100644 --- a/resources/metadata/abapEnvironmentBuild.yaml +++ b/resources/metadata/abapEnvironmentBuild.yaml @@ -203,7 +203,7 @@ spec: - STEPS - name: certificateNames type: "[]string" - description: certificates for the backend system, this certificates needs to be stored in .pipeline/trustStore + description: "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore" mandatory: false scope: - PARAMETERS diff --git a/resources/metadata/abapEnvironmentCheckoutBranch.yaml b/resources/metadata/abapEnvironmentCheckoutBranch.yaml index d85035369c..37d2729b76 100644 --- a/resources/metadata/abapEnvironmentCheckoutBranch.yaml +++ b/resources/metadata/abapEnvironmentCheckoutBranch.yaml @@ -127,6 +127,15 @@ spec: - name: cloudFoundry/serviceKey - name: cloudFoundry/serviceKeyName - name: cfServiceKeyName + - name: certificateNames + type: "[]string" + description: "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore" + mandatory: false + scope: + - PARAMETERS + - STAGES + - STEPS + - GENERAL containers: - name: cf image: ppiper/cf-cli:v12 diff --git a/resources/metadata/abapEnvironmentCloneGitRepo.yaml b/resources/metadata/abapEnvironmentCloneGitRepo.yaml index 9ec1385f34..e3d3828388 100644 --- a/resources/metadata/abapEnvironmentCloneGitRepo.yaml +++ b/resources/metadata/abapEnvironmentCloneGitRepo.yaml @@ -127,6 +127,15 @@ spec: - name: cloudFoundry/serviceKey - name: cloudFoundry/serviceKeyName - name: cfServiceKey + - name: certificateNames + type: "[]string" + description: "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore" + mandatory: false + scope: + - PARAMETERS + - STAGES + - STEPS + - GENERAL containers: - name: cf image: ppiper/cf-cli:v12 diff --git a/resources/metadata/abapEnvironmentCreateTag.yaml b/resources/metadata/abapEnvironmentCreateTag.yaml index a5c4b51394..947db9d7f2 100644 --- a/resources/metadata/abapEnvironmentCreateTag.yaml +++ b/resources/metadata/abapEnvironmentCreateTag.yaml @@ -157,6 +157,15 @@ spec: - name: cloudFoundry/serviceKey - name: cloudFoundry/serviceKeyName - name: cfServiceKey + - name: certificateNames + type: "[]string" + description: "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore" + mandatory: false + scope: + - PARAMETERS + - STAGES + - STEPS + - GENERAL containers: - name: cf image: ppiper/cf-cli:v12 diff --git a/resources/metadata/abapEnvironmentPullGitRepo.yaml b/resources/metadata/abapEnvironmentPullGitRepo.yaml index a27665058e..ba3da2f3e9 100644 --- a/resources/metadata/abapEnvironmentPullGitRepo.yaml +++ b/resources/metadata/abapEnvironmentPullGitRepo.yaml @@ -140,6 +140,15 @@ spec: scope: - PARAMETERS default: false + - name: certificateNames + type: "[]string" + description: "file names of trusted (self-signed) server certificates - need to be stored in .pipeline/trustStore" + mandatory: false + scope: + - PARAMETERS + - STAGES + - STEPS + - GENERAL containers: - name: cf image: ppiper/cf-cli:v12