1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-04 04:07:16 +02:00

ApiProviderList Command (#3879)

* ApiProviderList Command

* Metadata Fix

* Metadata Fix

* CodeReview Fixes

* Documentation Fixes

* unit test fix

Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>
This commit is contained in:
Mayur Belur Mohan 2022-07-07 18:18:59 +05:30 committed by GitHub
parent 000e3ab4a9
commit 5931415d9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 573 additions and 1 deletions

58
cmd/apiProviderList.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 apiProviderList(config apiProviderListOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *apiProviderListCommonPipelineEnvironment) {
httpClient := &piperhttp.Client{}
err := runApiProviderList(&config, telemetryData, httpClient, commonPipelineEnvironment)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runApiProviderList(config *apiProviderListOptions, telemetryData *telemetry.CustomData, httpClient piperhttp.Sender, commonPipelineEnvironment *apiProviderListCommonPipelineEnvironment) error {
apimData := apim.Bundle{APIServiceKey: config.APIServiceKey, Client: httpClient}
err := apim.Utils.InitAPIM(&apimData)
if err != nil {
return err
}
return getApiProviderList(config, apimData, commonPipelineEnvironment)
}
func getApiProviderList(config *apiProviderListOptions, apistruct apim.Bundle, commonPipelineEnvironment *apiProviderListCommonPipelineEnvironment) 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")
}
getApiProviderListURL := fmt.Sprintf("%s/apiportal/api/1.0/Management.svc/APIProviders%s", apistruct.Host, odataFilters)
header := make(http.Header)
header.Add("Accept", "application/json")
apiProviderListResp, httpErr := httpClient.SendRequest(httpMethod, getApiProviderListURL, nil, header, nil)
failureMessage := "Failed to get List of API Providers"
successMessage := "Successfully retrieved the api provider list from API Portal"
httpGetRequestParameters := cpi.HttpFileUploadRequestParameters{
ErrMessage: failureMessage,
Response: apiProviderListResp,
HTTPMethod: httpMethod,
HTTPURL: getApiProviderListURL,
HTTPErr: httpErr,
SuccessMessage: successMessage}
resp, err := cpi.HTTPUploadUtils.HandleHTTPGetRequestResponse(httpGetRequestParameters)
commonPipelineEnvironment.custom.APIProviderList = resp
return err
}

View File

@ -0,0 +1,286 @@
// 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 apiProviderListOptions 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 apiProviderListCommonPipelineEnvironment struct {
custom struct {
APIProviderList string
}
}
func (p *apiProviderListCommonPipelineEnvironment) persist(path, resourceName string) {
content := []struct {
category string
name string
value interface{}
}{
{category: "custom", name: "apiProviderList", value: p.custom.APIProviderList},
}
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")
}
}
// ApiProviderListCommand Get a full List of all API providers from the API Portal
func ApiProviderListCommand() *cobra.Command {
const STEP_NAME = "apiProviderList"
metadata := apiProviderListMetadata()
var stepConfig apiProviderListOptions
var startTime time.Time
var commonPipelineEnvironment apiProviderListCommonPipelineEnvironment
var logCollector *log.CollectorHook
var splunkClient *splunk.Splunk
telemetryClient := &telemetry.Telemetry{}
var createApiProviderListCmd = &cobra.Command{
Use: STEP_NAME,
Short: "Get a full List of all API providers from the API Portal",
Long: `With this step, you can get a list of all API providers from the API Portal using the OData API. Learn more about the API Management API for getting list of an API Providers [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)
}
if err = log.RegisterANSHookIfConfigured(GeneralConfig.CorrelationID); err != nil {
log.Entry().WithError(err).Warn("failed to set up SAP Alert Notification Service log hook")
}
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)
}
apiProviderList(stepConfig, &stepTelemetryData, &commonPipelineEnvironment)
stepTelemetryData.ErrorCode = "0"
log.Entry().Info("SUCCESS")
},
}
addApiProviderListFlags(createApiProviderListCmd, &stepConfig)
return createApiProviderListCmd
}
func addApiProviderListFlags(cmd *cobra.Command, stepConfig *apiProviderListOptions) {
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 apiProviderListMetadata() config.StepData {
var theMetaData = config.StepData{
Metadata: config.StepMetadata{
Name: "apiProviderList",
Aliases: []config.Alias{},
Description: "Get a full List of all API providers 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/apiProviderList"},
},
},
},
},
},
}
return theMetaData
}

View File

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

View File

@ -0,0 +1,53 @@
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 TestRunApiProviderList(t *testing.T) {
t.Parallel()
t.Run("Get API providers successfull test", func(t *testing.T) {
config := getDefaultOptionsForApiProviderList()
httpClientMock := &apimhttp.HttpMockAPIM{StatusCode: 200, ResponseBody: `{"some": "test"}`}
seOut := apiProviderListCommonPipelineEnvironment{}
apim := apim.Bundle{APIServiceKey: config.APIServiceKey, Client: httpClientMock}
// test
err := getApiProviderList(&config, apim, &seOut)
// assert
if assert.NoError(t, err) {
assert.EqualValues(t, seOut.custom.APIProviderList, "{\"some\": \"test\"}")
t.Run("check url", func(t *testing.T) {
assert.Equal(t, "/apiportal/api/1.0/Management.svc/APIProviders?orderby=value&$select=name&$top=2", httpClientMock.URL)
})
t.Run("check method", func(t *testing.T) {
assert.Equal(t, "GET", httpClientMock.Method)
})
}
})
t.Run("Get API provider failed test", func(t *testing.T) {
config := getDefaultOptionsForApiProviderList()
httpClientMock := &apimhttp.HttpMockAPIM{StatusCode: 400}
seOut := apiProviderListCommonPipelineEnvironment{}
apim := apim.Bundle{APIServiceKey: config.APIServiceKey, Client: httpClientMock}
// test
err := getApiProviderList(&config, apim, &seOut)
// assert
assert.EqualError(t, err, "HTTP GET request to /apiportal/api/1.0/Management.svc/APIProviders?orderby=value&$select=name&$top=2 failed with error: : Bad Request")
})
}
func getDefaultOptionsForApiProviderList() apiProviderListOptions {
return apiProviderListOptions{
APIServiceKey: apimhttp.GetServiceKey(),
Top: 2,
Select: "name",
Orderby: "value",
}
}

View File

@ -29,6 +29,7 @@ func GetAllStepMetadata() map[string]config.StepData {
"apiKeyValueMapDownload": apiKeyValueMapDownloadMetadata(),
"apiKeyValueMapUpload": apiKeyValueMapUploadMetadata(),
"apiProviderDownload": apiProviderDownloadMetadata(),
"apiProviderList": apiProviderListMetadata(),
"apiProviderUpload": apiProviderUploadMetadata(),
"apiProxyDownload": apiProxyDownloadMetadata(),
"apiProxyList": apiProxyListMetadata(),

View File

@ -190,6 +190,7 @@ func Execute() {
rootCmd.AddCommand(AwsS3UploadCommand())
rootCmd.AddCommand(ApiProxyListCommand())
rootCmd.AddCommand(AnsSendEventCommand())
rootCmd.AddCommand(ApiProviderListCommand())
addRootFlags(rootCmd)

View File

@ -0,0 +1,49 @@
# ${docGenStepName}
## ${docGenDescription}
With this step, you can retrieve all the API providers from the API portal. An API provider is a concept in API Management, capability of SAP Integration Suite, which defines the connection details for services running on specific hosts whose details you want to access.
You use an API provider to define not only the details of the host you want an application to reach, but also to define any further details that are necessary to establish the connection, for example, proxy settings. For more details, see the blog [API Providers](https://blogs.sap.com/2017/07/27/blog-series-api-providers/)
To consume the ApiProviderList 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 ApiProviderList 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 ApiProviderList step to get the api providers list from the API Portal.
* ApiProviderList only supports GET operation.
## Prerequisites
## ${docGenParameters}
## ${docGenConfiguration}
## ${docJenkinsPluginDependencies}
## Example
Configuration example for a `Jenkinsfile`:
```groovy
apiProviderList script: this
```
Configuration example for a YAML file(for example `.pipeline/config.yaml`):
```yaml
steps:
<...>
apiProviderList:
apimApiServiceKeyCredentialsId: 'MY_API_SERVICE_KEY'
Top: MY_API_PROVIDER_GET_N_ENTITIES
Skip: MY_API_PROVIDER_SKIP_N_ENTITIES
Filter: MY_API_PROVIDER_FILTER_BY_ENTITY_FIELD
Orderby: MY_API_PROVIDER_ORDER_BY_ENTITY_FIELD
Count: MY_API_PROVIDER_ORDER_ENTITY_COUNT
Search: MY_API_PROVIDER_SEARCH_BY_ENTITY_FIELD
Select: MY_API_PROVIDER_SELECT_BY_ENTITY_FIELD
Expand: MY_API_PROVIDER_EXPAND_BY_ENTITY_FIELD
```

View File

@ -74,6 +74,7 @@ nav:
- apiProxyDownload: steps/apiProxyDownload.md
- apiProxyList: steps/apiProxyList.md
- apiProviderDownload: steps/apiProviderDownload.md
- apiProviderList: steps/apiProviderList.md
- apiProviderUpload: steps/apiProviderUpload.md
- apiProxyUpload: steps/apiProxyUpload.md
- artifactPrepareVersion: steps/artifactPrepareVersion.md

View File

@ -0,0 +1,94 @@
metadata:
name: apiProviderList
description: Get a full List of all API providers from the API Portal
longDescription: |
With this step, you can get a list of all API providers from the API Portal using the OData API. Learn more about the API Management API for getting list of an API Providers [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/apiProviderList

View File

@ -222,7 +222,8 @@ public class CommonStepsTest extends BasePiperTest{
'apiProxyList', //implementing new golang pattern without fields
'azureBlobUpload',
'awsS3Upload',
'ansSendEvent'
'ansSendEvent',
'apiProviderList', //implementing new golang pattern without fields
]
@Test

View File

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