1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-11-28 08:49:44 +02:00

ApiProxyList Command (#3794)

* ApiProxyList Command

* CodeReview Fixes

* CodeReview Fixes

* CodeReview FIxes

* CodeReview Fixes

* CodeReview FIxes

* CodeReview Fixes

* fixing unit test

* doc fixes

* Update documentation/docs/steps/apiProxyList.md

Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>

* CodeReview Fixes

* CodeReview Fixes

* CodeReview Fixes

* codereview fix

Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>
This commit is contained in:
Mayur Belur Mohan 2022-06-21 16:38:00 +05:30 committed by GitHub
parent 8768d2bb74
commit cdea4b7713
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 656 additions and 0 deletions

58
cmd/apiProxyList.go Normal file
View File

@ -0,0 +1,58 @@
package cmd
import (
"fmt"
"net/http"
"github.com/SAP/jenkins-library/pkg/apim"
"github.com/SAP/jenkins-library/pkg/cpi"
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 apiProxyList(config apiProxyListOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *apiProxyListCommonPipelineEnvironment) {
httpClient := &piperhttp.Client{}
err := runApiProxyList(&config, telemetryData, httpClient, commonPipelineEnvironment)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runApiProxyList(config *apiProxyListOptions, telemetryData *telemetry.CustomData, httpClient piperhttp.Sender, commonPipelineEnvironment *apiProxyListCommonPipelineEnvironment) error {
apimData := apim.Bundle{APIServiceKey: config.APIServiceKey, Client: httpClient}
err := apim.Utils.InitAPIM(&apimData)
if err != nil {
return err
}
return getApiProxyList(config, apimData, commonPipelineEnvironment)
}
func getApiProxyList(config *apiProxyListOptions, apistruct apim.Bundle, commonPipelineEnvironment *apiProxyListCommonPipelineEnvironment) error {
httpClient := apistruct.Client
httpMethod := http.MethodGet
odataFilterInputs := apim.OdataParameters{Filter: config.Filter, Search: config.Search,
Top: config.Top, Skip: config.Skip, Orderby: config.Orderby,
Select: config.Select, Expand: config.Expand}
odataFilters, urlErr := apim.OdataUtils.MakeOdataQuery(&odataFilterInputs)
if urlErr != nil {
return errors.Wrap(urlErr, "failed to create odata filter")
}
getApiProxyListURL := fmt.Sprintf("%s/apiportal/api/1.0/Management.svc/APIProxies%s", apistruct.Host, odataFilters)
header := make(http.Header)
header.Add("Accept", "application/json")
apiProxyListResp, httpErr := httpClient.SendRequest(httpMethod, getApiProxyListURL, nil, header, nil)
failureMessage := "Failed to get List of API Proxy"
successMessage := "Successfully retrieved the api proxy list from API Portal"
httpGetRequestParameters := cpi.HttpFileUploadRequestParameters{
ErrMessage: failureMessage,
Response: apiProxyListResp,
HTTPMethod: httpMethod,
HTTPURL: getApiProxyListURL,
HTTPErr: httpErr,
SuccessMessage: successMessage}
resp, err := cpi.HTTPUploadUtils.HandleHTTPGetRequestResponse(httpGetRequestParameters)
commonPipelineEnvironment.custom.APIProxyList = resp
return err
}

View File

@ -0,0 +1,282 @@
// Code generated by piper's step-generator. DO NOT EDIT.
package cmd
import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/SAP/jenkins-library/pkg/splunk"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/validation"
"github.com/spf13/cobra"
)
type apiProxyListOptions struct {
APIServiceKey string `json:"apiServiceKey,omitempty"`
Top int `json:"top,omitempty"`
Skip int `json:"skip,omitempty"`
Filter string `json:"filter,omitempty"`
Count bool `json:"count,omitempty"`
Search string `json:"search,omitempty"`
Orderby string `json:"orderby,omitempty"`
Select string `json:"select,omitempty"`
Expand string `json:"expand,omitempty"`
}
type apiProxyListCommonPipelineEnvironment struct {
custom struct {
APIProxyList string
}
}
func (p *apiProxyListCommonPipelineEnvironment) persist(path, resourceName string) {
content := []struct {
category string
name string
value interface{}
}{
{category: "custom", name: "apiProxyList", value: p.custom.APIProxyList},
}
errCount := 0
for _, param := range content {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(param.category, param.name), param.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting piper environment.")
errCount++
}
}
if errCount > 0 {
log.Entry().Error("failed to persist Piper environment")
}
}
// ApiProxyListCommand Get the List of an API Proxy from the API Portal
func ApiProxyListCommand() *cobra.Command {
const STEP_NAME = "apiProxyList"
metadata := apiProxyListMetadata()
var stepConfig apiProxyListOptions
var startTime time.Time
var commonPipelineEnvironment apiProxyListCommonPipelineEnvironment
var logCollector *log.CollectorHook
var splunkClient *splunk.Splunk
telemetryClient := &telemetry.Telemetry{}
var createApiProxyListCmd = &cobra.Command{
Use: STEP_NAME,
Short: "Get the List of an API Proxy from the API Portal",
Long: `With this step you can get list of all API Proxy from the API Portal using the OData API. Learn more about the API Management API for getting list of an API proxy artifact [here](https://help.sap.com/viewer/66d066d903c2473f81ec33acfe2ccdb4/Cloud/en-US/e26b3320cd534ae4bc743af8013a8abb.html).`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
startTime = time.Now()
log.SetStepName(STEP_NAME)
log.SetVerbose(GeneralConfig.Verbose)
GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens)
path, _ := os.Getwd()
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
log.RegisterHook(fatalHook)
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
if err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
return err
}
log.RegisterSecret(stepConfig.APIServiceKey)
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
log.RegisterHook(&sentryHook)
}
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunkClient = &splunk.Splunk{}
logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
log.RegisterHook(logCollector)
}
validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages())
if err != nil {
return err
}
if err = validation.ValidateStruct(stepConfig); err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
return err
}
return nil
},
Run: func(_ *cobra.Command, _ []string) {
stepTelemetryData := telemetry.CustomData{}
stepTelemetryData.ErrorCode = "1"
handler := func() {
commonPipelineEnvironment.persist(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
config.RemoveVaultSecretFiles()
stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
stepTelemetryData.ErrorCategory = log.GetErrorCategory().String()
stepTelemetryData.PiperCommitHash = GitCommit
telemetryClient.SetData(&stepTelemetryData)
telemetryClient.Send()
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunkClient.Send(telemetryClient.GetData(), logCollector)
}
}
log.DeferExitHandler(handler)
defer handler()
telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
splunkClient.Initialize(GeneralConfig.CorrelationID,
GeneralConfig.HookConfig.SplunkConfig.Dsn,
GeneralConfig.HookConfig.SplunkConfig.Token,
GeneralConfig.HookConfig.SplunkConfig.Index,
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
}
apiProxyList(stepConfig, &stepTelemetryData, &commonPipelineEnvironment)
stepTelemetryData.ErrorCode = "0"
log.Entry().Info("SUCCESS")
},
}
addApiProxyListFlags(createApiProxyListCmd, &stepConfig)
return createApiProxyListCmd
}
func addApiProxyListFlags(cmd *cobra.Command, stepConfig *apiProxyListOptions) {
cmd.Flags().StringVar(&stepConfig.APIServiceKey, "apiServiceKey", os.Getenv("PIPER_apiServiceKey"), "Service key JSON string to access the API Management Runtime service instance of plan 'api'")
cmd.Flags().IntVar(&stepConfig.Top, "top", 0, "Show only the first n items.")
cmd.Flags().IntVar(&stepConfig.Skip, "skip", 0, "Skip the first n items.")
cmd.Flags().StringVar(&stepConfig.Filter, "filter", os.Getenv("PIPER_filter"), "Filter items by property values.")
cmd.Flags().BoolVar(&stepConfig.Count, "count", false, "Include count of items.")
cmd.Flags().StringVar(&stepConfig.Search, "search", os.Getenv("PIPER_search"), "Search items by search phrases.")
cmd.Flags().StringVar(&stepConfig.Orderby, "orderby", os.Getenv("PIPER_orderby"), "Order by property values.")
cmd.Flags().StringVar(&stepConfig.Select, "select", os.Getenv("PIPER_select"), "Select properties to be returned.")
cmd.Flags().StringVar(&stepConfig.Expand, "expand", os.Getenv("PIPER_expand"), "Expand related entities.")
cmd.MarkFlagRequired("apiServiceKey")
}
// retrieve step metadata
func apiProxyListMetadata() config.StepData {
var theMetaData = config.StepData{
Metadata: config.StepMetadata{
Name: "apiProxyList",
Aliases: []config.Alias{},
Description: "Get the List of an API Proxy from the API Portal",
},
Spec: config.StepSpec{
Inputs: config.StepInputs{
Secrets: []config.StepSecrets{
{Name: "apimApiServiceKeyCredentialsId", Description: "Jenkins secret text credential ID containing the service key to the API Management Runtime service instance of plan 'api'", Type: "jenkins"},
},
Parameters: []config.StepParameters{
{
Name: "apiServiceKey",
ResourceRef: []config.ResourceReference{
{
Name: "apimApiServiceKeyCredentialsId",
Param: "apiServiceKey",
Type: "secret",
},
},
Scope: []string{"PARAMETERS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_apiServiceKey"),
},
{
Name: "top",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "int",
Mandatory: false,
Aliases: []config.Alias{},
Default: 0,
},
{
Name: "skip",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "int",
Mandatory: false,
Aliases: []config.Alias{},
Default: 0,
},
{
Name: "filter",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_filter"),
},
{
Name: "count",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
Default: false,
},
{
Name: "search",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_search"),
},
{
Name: "orderby",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_orderby"),
},
{
Name: "select",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_select"),
},
{
Name: "expand",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_expand"),
},
},
},
Outputs: config.StepOutputs{
Resources: []config.StepResources{
{
Name: "commonPipelineEnvironment",
Type: "piperEnvironment",
Parameters: []map[string]interface{}{
{"name": "custom/apiProxyList"},
},
},
},
},
},
}
return theMetaData
}

View File

@ -0,0 +1,17 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestApiProxyListCommand(t *testing.T) {
t.Parallel()
testCmd := ApiProxyListCommand()
// only high level testing performed - details are tested in step generation procedure
assert.Equal(t, "apiProxyList", testCmd.Use, "command name incorrect")
}

54
cmd/apiProxyList_test.go Normal file
View File

@ -0,0 +1,54 @@
package cmd
import (
"testing"
"github.com/SAP/jenkins-library/pkg/apim"
apimhttp "github.com/SAP/jenkins-library/pkg/apim"
"github.com/stretchr/testify/assert"
)
func TestRunApiProxyList(t *testing.T) {
t.Parallel()
t.Run("Get API Proxy List successfull test", func(t *testing.T) {
config := getDefaultOptionsForApiProxyList()
httpClientMock := &apimhttp.HttpMockAPIM{StatusCode: 200, ResponseBody: `{"some": "test"}`}
seOut := apiProxyListCommonPipelineEnvironment{}
apim := apim.Bundle{APIServiceKey: config.APIServiceKey, Client: httpClientMock}
// test
err := getApiProxyList(&config, apim, &seOut)
// assert
if assert.NoError(t, err) {
assert.EqualValues(t, seOut.custom.APIProxyList, "{\"some\": \"test\"}")
t.Run("check url", func(t *testing.T) {
assert.Equal(t, "/apiportal/api/1.0/Management.svc/APIProxies?filter=isCopy+eq+false&$orderby=name&$skip=1&$top=4", httpClientMock.URL)
})
t.Run("check method", func(t *testing.T) {
assert.Equal(t, "GET", httpClientMock.Method)
})
}
})
t.Run("Get API Proxy List failed test", func(t *testing.T) {
config := getDefaultOptionsForApiProxyList()
httpClientMock := &apimhttp.HttpMockAPIM{StatusCode: 400}
seOut := apiProxyListCommonPipelineEnvironment{}
apim := apim.Bundle{APIServiceKey: config.APIServiceKey, Client: httpClientMock}
// test
err := getApiProxyList(&config, apim, &seOut)
// assert
assert.EqualError(t, err, "HTTP GET request to /apiportal/api/1.0/Management.svc/APIProxies?filter=isCopy+eq+false&$orderby=name&$skip=1&$top=4 failed with error: : Bad Request")
})
}
func getDefaultOptionsForApiProxyList() apiProxyListOptions {
return apiProxyListOptions{
APIServiceKey: apimhttp.GetServiceKey(),
Top: 4,
Skip: 1,
Filter: "isCopy eq false",
Orderby: "name",
}
}

View File

@ -30,6 +30,7 @@ func GetAllStepMetadata() map[string]config.StepData {
"apiProviderDownload": apiProviderDownloadMetadata(), "apiProviderDownload": apiProviderDownloadMetadata(),
"apiProviderUpload": apiProviderUploadMetadata(), "apiProviderUpload": apiProviderUploadMetadata(),
"apiProxyDownload": apiProxyDownloadMetadata(), "apiProxyDownload": apiProxyDownloadMetadata(),
"apiProxyList": apiProxyListMetadata(),
"apiProxyUpload": apiProxyUploadMetadata(), "apiProxyUpload": apiProxyUploadMetadata(),
"artifactPrepareVersion": artifactPrepareVersionMetadata(), "artifactPrepareVersion": artifactPrepareVersionMetadata(),
"awsS3Upload": awsS3UploadMetadata(), "awsS3Upload": awsS3UploadMetadata(),

View File

@ -187,6 +187,7 @@ func Execute() {
rootCmd.AddCommand(PythonBuildCommand()) rootCmd.AddCommand(PythonBuildCommand())
rootCmd.AddCommand(AzureBlobUploadCommand()) rootCmd.AddCommand(AzureBlobUploadCommand())
rootCmd.AddCommand(AwsS3UploadCommand()) rootCmd.AddCommand(AwsS3UploadCommand())
rootCmd.AddCommand(ApiProxyListCommand())
addRootFlags(rootCmd) addRootFlags(rootCmd)

View File

@ -0,0 +1,49 @@
# ${docGenStepName}
## ${docGenDescription}
With this step, you can retrieve all the API proxies from the API portal. An API Proxy is a concept in API Management, capability of SAP Integration Suite, which anonymizes any HTTP endpoints like REST, OData, or SOAP and enhance it with policies and routes.
An API proxy is a discrete representation of an API. It is implemented as a set of configuration files, policies, and code snippets that rely on the resource information provided by API Management. For more information, see the document [API Proxy](https://help.sap.com/doc/654e5912ee554d46bcc6347599fb2096/CLOUD/en-US/Unit%2004.3%20-%20API%20Proxy%20-%20API%20Resource.pdf/)
To consume the ApiProxyList step, proceed as follows:
* Copy the SAP API management service key from the SAP BTP cockpit. Go to instance and subscriptions &rarr; service API Management, API portal, which was created under apiportal-apiaccess plan.
* Store your service key created for API Management in the Jenkins server as a secret text.
* Create a new Jenkins pipeline designated for the ApiProxyList step.
* Execute the pipeline and validate the step exection results as explained in the blog [Integration Suite Piper commands](https://blogs.sap.com/2022/01/05/orking-with-integration-suite-piper-commands/)
* Use the ApiProxyList step to get the api proxy list from the API portal.
* ApiProxyList only supports GET operation.
## Prerequisites
## ${docGenParameters}
## ${docGenConfiguration}
## ${docJenkinsPluginDependencies}
## Example
Configuration example for a `Jenkinsfile`:
```groovy
apiProxyList script: this
```
Configuration example for a YAML file(for example `.pipeline/config.yaml`):
```yaml
steps:
<...>
apiProxyList:
apimApiServiceKeyCredentialsId: 'MY_API_SERVICE_KEY'
Top: MY_API_PROXY_GET_N_ENTITIES
Skip: MY_API_PROXY_SKIP_N_ENTITIES
Filter: MY_API_PROXY_FILTER_BY_ENTITY_FIELD
Orderby: MY_API_PROXY_ORDER_BY_ENTITY_FIELD
Count: MY_API_PROXY_ORDER_ENTITY_COUNT
Search: MY_API_PROXY_SEARCH_BY_ENTITY_FIELD
Select: MY_API_PROXY_SELECT_BY_ENTITY_FIELD
Expand: MY_API_PROXY_EXPAND_BY_ENTITY_FIELD
```

View File

@ -72,6 +72,7 @@ nav:
- apiKeyValueMapDownload: steps/apiKeyValueMapDownload.md - apiKeyValueMapDownload: steps/apiKeyValueMapDownload.md
- apiKeyValueMapUpload: steps/apiKeyValueMapUpload.md - apiKeyValueMapUpload: steps/apiKeyValueMapUpload.md
- apiProxyDownload: steps/apiProxyDownload.md - apiProxyDownload: steps/apiProxyDownload.md
- apiProxyList: steps/apiProxyList.md
- apiProviderDownload: steps/apiProviderDownload.md - apiProviderDownload: steps/apiProviderDownload.md
- apiProviderUpload: steps/apiProviderUpload.md - apiProviderUpload: steps/apiProviderUpload.md
- apiProxyUpload: steps/apiProxyUpload.md - apiProxyUpload: steps/apiProxyUpload.md

1
go.mod
View File

@ -250,6 +250,7 @@ require (
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/oracle/oci-go-sdk v13.1.0+incompatible // indirect github.com/oracle/oci-go-sdk v13.1.0+incompatible // indirect
github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect

2
go.sum
View File

@ -1557,6 +1557,8 @@ github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otz
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c h1:Gcce/r5tSQeprxswXXOwQ/RBU1bjQWVd9dB7QKoPXBE=
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c/go.mod h1:1iCZ0433JJMecYqCa+TdWA9Pax8MGl4ByuNDZ7eSnQY=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=

View File

@ -3,10 +3,12 @@ package apim
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
"github.com/SAP/jenkins-library/pkg/cpi" "github.com/SAP/jenkins-library/pkg/cpi"
piperhttp "github.com/SAP/jenkins-library/pkg/http" piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/xsuaa" "github.com/SAP/jenkins-library/pkg/xsuaa"
"github.com/pasztorpisti/qs"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -16,6 +18,18 @@ type Utils interface {
IsPayloadJSON() bool IsPayloadJSON() bool
} }
//OdataUtils for apim
type OdataUtils interface {
MakeOdataQuery() (string, error)
}
//OdataParameters struct
type OdataParameters struct {
Filter, Search string
Top, Skip int
Orderby, Select, Expand string
}
//Bundle struct //Bundle struct
type Bundle struct { type Bundle struct {
APIServiceKey, Host, Payload string APIServiceKey, Host, Payload string
@ -51,3 +65,15 @@ func (apim *Bundle) IsPayloadJSON() bool {
var js json.RawMessage var js json.RawMessage
return json.Unmarshal([]byte(apim.Payload), &js) == nil return json.Unmarshal([]byte(apim.Payload), &js) == nil
} }
func (odataFilters *OdataParameters) MakeOdataQuery() (string, error) {
customMarshaler := qs.NewMarshaler(&qs.MarshalOptions{
DefaultMarshalPresence: qs.OmitEmpty,
})
values, encodeErr := customMarshaler.Marshal(odataFilters)
if encodeErr == nil && len(values) > 0 {
values = "?" + strings.ReplaceAll(values, "&", "&$")
}
return values, encodeErr
}

View File

@ -0,0 +1,27 @@
package apim
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestOdataQueryInitExisting(t *testing.T) {
t.Run("MakeOdataQuery- Success Test", func(t *testing.T) {
odataFilterInputs := OdataParameters{Filter: "isCopy eq false", Search: "",
Top: 4, Skip: 1, Orderby: "name",
Select: "", Expand: ""}
odataFilters, err := OdataUtils.MakeOdataQuery(&odataFilterInputs)
assert.NoError(t, err)
assert.Equal(t, "?filter=isCopy+eq+false&$orderby=name&$skip=1&$top=4", odataFilters)
})
t.Run("MakeOdataQuery- empty odata filters Test", func(t *testing.T) {
odataFilterInputs := OdataParameters{Filter: "", Search: "",
Top: 0, Skip: 0, Orderby: "",
Select: "", Expand: ""}
odataFilters, err := OdataUtils.MakeOdataQuery(&odataFilterInputs)
assert.NoError(t, err)
assert.Equal(t, "", odataFilters)
})
}

View File

@ -30,6 +30,7 @@ type HttpCPIUtils interface {
//HTTPUploadUtils for CPI //HTTPUploadUtils for CPI
type HTTPUploadUtils interface { type HTTPUploadUtils interface {
HandleHTTPFileUploadResponse() error HandleHTTPFileUploadResponse() error
HandleHTTPGetRequestResponse() (string, error)
} }
//TokenParameters struct //TokenParameters struct
@ -190,3 +191,32 @@ func (httpFileUploadRequestParameters HttpFileUploadRequestParameters) HandleHTT
} }
return errors.Errorf("%s, Response Status code: %v", httpFileUploadRequestParameters.ErrMessage, response.StatusCode) return errors.Errorf("%s, Response Status code: %v", httpFileUploadRequestParameters.ErrMessage, response.StatusCode)
} }
// HandleHTTPGetRequestResponse - Handle the GET Request response data
func (httpGetRequestParameters HttpFileUploadRequestParameters) HandleHTTPGetRequestResponse() (string, error) {
response := httpGetRequestParameters.Response
httpErr := httpGetRequestParameters.HTTPErr
if response != nil && response.Body != nil {
defer response.Body.Close()
}
if response == nil {
return "", errors.Errorf("did not retrieve a HTTP response: %v", httpErr)
}
if response.StatusCode == http.StatusOK {
responseBody, readErr := ioutil.ReadAll(response.Body)
if readErr != nil {
return "", errors.Wrapf(readErr, "HTTP response body could not be read, response status code: %v", response.StatusCode)
}
return string(responseBody), nil
}
if httpErr != nil {
responseBody, readErr := ioutil.ReadAll(response.Body)
if readErr != nil {
return "", errors.Wrapf(readErr, "HTTP response body could not be read, Response status code: %v", response.StatusCode)
}
log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code: %v", string(responseBody), response.StatusCode)
return "", errors.Wrapf(httpErr, "HTTP %v request to %v failed with error: %v", httpGetRequestParameters.HTTPMethod, httpGetRequestParameters.HTTPURL, string(responseBody))
}
return "", errors.Errorf("%s, Response Status code: %v", httpGetRequestParameters.ErrMessage, response.StatusCode)
}

View File

@ -0,0 +1,94 @@
metadata:
name: apiProxyList
description: Get the List of an API Proxy from the API Portal
longDescription: |
With this step you can get list of all API Proxy from the API Portal using the OData API. Learn more about the API Management API for getting list of an API proxy artifact [here](https://help.sap.com/viewer/66d066d903c2473f81ec33acfe2ccdb4/Cloud/en-US/e26b3320cd534ae4bc743af8013a8abb.html).
spec:
inputs:
secrets:
- name: apimApiServiceKeyCredentialsId
description: Jenkins secret text credential ID containing the service key to the API Management Runtime service instance of plan 'api'
type: jenkins
params:
- name: apiServiceKey
type: string
description: Service key JSON string to access the API Management Runtime service instance of plan 'api'
scope:
- PARAMETERS
mandatory: true
secret: true
resourceRef:
- name: apimApiServiceKeyCredentialsId
type: secret
param: apiServiceKey
- name: top
type: int
description: Show only the first n items.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
- name: skip
type: int
description: Skip the first n items.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
- name: filter
type: string
description: Filter items by property values.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
- name: count
type: bool
description: Include count of items.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
- name: search
type: string
description: Search items by search phrases.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
- name: orderby
type: string
description: Order by property values.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
- name: select
type: string
description: Select properties to be returned.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
- name: expand
type: string
description: Expand related entities.
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: false
outputs:
resources:
- name: commonPipelineEnvironment
type: piperEnvironment
params:
- name: custom/apiProxyList

View File

@ -217,6 +217,8 @@ public class CommonStepsTest extends BasePiperTest{
'apiKeyValueMapUpload', //implementing new golang pattern without fields 'apiKeyValueMapUpload', //implementing new golang pattern without fields
'apiProviderUpload', //implementing new golang pattern without fields 'apiProviderUpload', //implementing new golang pattern without fields
'pythonBuild', //implementing new golang pattern without fields 'pythonBuild', //implementing new golang pattern without fields
'awsS3Upload',
'apiProxyList', //implementing new golang pattern without fields
'azureBlobUpload', 'azureBlobUpload',
'awsS3Upload' 'awsS3Upload'
] ]

11
vars/apiProxyList.groovy Normal file
View File

@ -0,0 +1,11 @@
import groovy.transform.Field
@Field String STEP_NAME = getClass().getName()
@Field String METADATA_FILE = 'metadata/apiProxyList.yaml'
void call(Map parameters = [:]) {
List credentials = [
[type: 'token', id: 'apimApiServiceKeyCredentialsId', env: ['PIPER_apiServiceKey']]
]
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials)
}