mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
Dont work upon a global command.Command instance inside cloudfoundry package (#1771)
o Up to now we work on a private and shared instance of command.Command inside the cloudfounrdy package. We need to be able either configure this instance (environment variables) according to the use case. One option is to hand over an already configured instance which is used elsewhere. This is what we do with this commit. o With this commit we remove the instance which is shared within the cloudfounrdy package and to provide an instance with a receiver which gets handed over to the functions. Hence we are thread save: parallel invoctation of e.g. Login will not affect each other.
This commit is contained in:
parent
db13b2f9ce
commit
bda9a9ffba
@ -231,7 +231,8 @@ func checkHost(config abapEnvironmentRunATCCheckOptions, details connectionDetai
|
||||
return details, errors.New("Parameters missing. Please provide EITHER the Host of the ABAP server OR the Cloud Foundry ApiEndpoint, Organization, Space, Service Instance and a corresponding Service Key for the Communication Scenario SAP_COM_0510")
|
||||
}
|
||||
var abapServiceKey cloudfoundry.ServiceKey
|
||||
abapServiceKey, err = cloudfoundry.ReadServiceKeyAbapEnvironment(cfconfig, true)
|
||||
cf := cloudfoundry.CFUtils{Exec: &command.Command{}}
|
||||
abapServiceKey, err = cf.ReadServiceKeyAbapEnvironment(cfconfig, true)
|
||||
if err != nil {
|
||||
return details, fmt.Errorf("Reading Service Key failed: %w", err)
|
||||
}
|
||||
|
@ -10,14 +10,18 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
)
|
||||
|
||||
var c command.ExecRunner = &command.Command{}
|
||||
|
||||
//LoginCheck checks if user is logged in to Cloud Foundry.
|
||||
//If user is not logged in 'cf api' command will return string that contains 'User is not logged in' only if user is not logged in.
|
||||
//If the returned string doesn't contain the substring 'User is not logged in' we know he is logged in.
|
||||
func LoginCheck(options LoginOptions) (bool, error) {
|
||||
func (cf *CFUtils) LoginCheck(options LoginOptions) (bool, error) {
|
||||
var err error
|
||||
|
||||
_c := cf.Exec
|
||||
|
||||
if _c == nil {
|
||||
_c = &command.Command{}
|
||||
}
|
||||
|
||||
if options.CfAPIEndpoint == "" {
|
||||
return false, errors.New("Cloud Foundry API endpoint parameter missing. Please provide the Cloud Foundry Endpoint")
|
||||
}
|
||||
@ -25,12 +29,26 @@ func LoginCheck(options LoginOptions) (bool, error) {
|
||||
//Check if logged in --> Cf api command responds with "not logged in" if positive
|
||||
var cfCheckLoginScript = append([]string{"api", options.CfAPIEndpoint}, options.CfAPIOpts...)
|
||||
|
||||
defer func() {
|
||||
// We set it back to what is set from the generated stub. Of course this is not
|
||||
// fully accurate in case we create our own instance above (nothing handed in via
|
||||
// the receiver).
|
||||
// Would be better to remember the old stdout and set back to this.
|
||||
// But command.Command does not allow to get the currently set
|
||||
// stdout handler.
|
||||
// Reason for changing the output stream here: we need to parse the output
|
||||
// of the command issued here in order to check if we are already logged in.
|
||||
// This is expected to change soon to a boolean variable where we remember the
|
||||
// login state.
|
||||
_c.Stdout(log.Writer())
|
||||
}()
|
||||
|
||||
var cfLoginBytes bytes.Buffer
|
||||
c.Stdout(&cfLoginBytes)
|
||||
_c.Stdout(&cfLoginBytes)
|
||||
|
||||
var result string
|
||||
|
||||
err = c.RunExecutable("cf", cfCheckLoginScript...)
|
||||
err = _c.RunExecutable("cf", cfCheckLoginScript...)
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to check if logged in: %w", err)
|
||||
@ -52,17 +70,22 @@ func LoginCheck(options LoginOptions) (bool, error) {
|
||||
|
||||
//Login logs user in to Cloud Foundry via cf cli.
|
||||
//Checks if user is logged in first, if not perform 'cf login' command with appropriate parameters
|
||||
func Login(options LoginOptions) error {
|
||||
|
||||
func (cf *CFUtils) Login(options LoginOptions) error {
|
||||
var err error
|
||||
|
||||
_c := cf.Exec
|
||||
|
||||
if _c == nil {
|
||||
_c = &command.Command{}
|
||||
}
|
||||
|
||||
if options.CfAPIEndpoint == "" || options.CfOrg == "" || options.CfSpace == "" || options.Username == "" || options.Password == "" {
|
||||
return fmt.Errorf("Failed to login to Cloud Foundry: %w", errors.New("Parameters missing. Please provide the Cloud Foundry Endpoint, Org, Space, Username and Password"))
|
||||
}
|
||||
|
||||
var loggedIn bool
|
||||
|
||||
loggedIn, err = LoginCheck(options)
|
||||
loggedIn, err = cf.LoginCheck(options)
|
||||
|
||||
if loggedIn == true {
|
||||
return err
|
||||
@ -82,7 +105,7 @@ func Login(options LoginOptions) error {
|
||||
|
||||
log.Entry().WithField("cfAPI:", options.CfAPIEndpoint).WithField("cfOrg", options.CfOrg).WithField("space", options.CfSpace).Info("Logging into Cloud Foundry..")
|
||||
|
||||
err = c.RunExecutable("cf", cfLoginScript...)
|
||||
err = _c.RunExecutable("cf", cfLoginScript...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -94,12 +117,19 @@ func Login(options LoginOptions) error {
|
||||
|
||||
//Logout logs User out of Cloud Foundry
|
||||
//Logout can be perforned via 'cf logout' command regardless if user is logged in or not
|
||||
func Logout() error {
|
||||
func (cf *CFUtils) Logout() error {
|
||||
|
||||
_c := cf.Exec
|
||||
|
||||
if _c == nil {
|
||||
_c = &command.Command{}
|
||||
}
|
||||
|
||||
var cfLogoutScript = "logout"
|
||||
|
||||
log.Entry().Info("Logging out of Cloud Foundry")
|
||||
|
||||
err := c.RunExecutable("cf", cfLogoutScript)
|
||||
err := _c.RunExecutable("cf", cfLogoutScript)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
|
||||
}
|
||||
@ -117,3 +147,13 @@ type LoginOptions struct {
|
||||
CfAPIOpts []string
|
||||
CfLoginOpts []string
|
||||
}
|
||||
|
||||
// CFUtils ...
|
||||
type CFUtils struct {
|
||||
// In order to avoid clashes between parallel workflows requiring cf login/logout
|
||||
// this instance of command.ExecRunner can be configured accordingly by settings the
|
||||
// environment variables CF_HOME to distict directories.
|
||||
// In order to ensure plugins installed to the cf cli are found environment variables
|
||||
// CF_PLUGIN_HOME can be set accordingly.
|
||||
Exec command.ExecRunner
|
||||
}
|
||||
|
@ -18,14 +18,10 @@ func TestCloudFoundryLoginCheck(t *testing.T) {
|
||||
|
||||
m := &mock.ExecMockRunner{}
|
||||
|
||||
defer func() {
|
||||
c = &command.Command{}
|
||||
}()
|
||||
c = m
|
||||
|
||||
t.Run("CF Login check: missing endpoint parameter", func(t *testing.T) {
|
||||
cfconfig := LoginOptions{}
|
||||
loggedIn, err := LoginCheck(cfconfig)
|
||||
cf := CFUtils{Exec: m}
|
||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
||||
assert.False(t, loggedIn)
|
||||
assert.EqualError(t, err, "Cloud Foundry API endpoint parameter missing. Please provide the Cloud Foundry Endpoint")
|
||||
})
|
||||
@ -38,7 +34,8 @@ func TestCloudFoundryLoginCheck(t *testing.T) {
|
||||
cfconfig := LoginOptions{
|
||||
CfAPIEndpoint: "https://api.endpoint.com",
|
||||
}
|
||||
loggedIn, err := LoginCheck(cfconfig)
|
||||
cf := CFUtils{Exec: m}
|
||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
||||
assert.False(t, loggedIn)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, []mock.ExecCall{mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}}}, m.Calls)
|
||||
@ -51,7 +48,8 @@ func TestCloudFoundryLoginCheck(t *testing.T) {
|
||||
cfconfig := LoginOptions{
|
||||
CfAPIEndpoint: "https://api.endpoint.com",
|
||||
}
|
||||
loggedIn, err := LoginCheck(cfconfig)
|
||||
cf := CFUtils{Exec: m}
|
||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
||||
if assert.NoError(t, err) {
|
||||
assert.True(t, loggedIn)
|
||||
assert.Equal(t, []mock.ExecCall{mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}}}, m.Calls)
|
||||
@ -67,7 +65,9 @@ func TestCloudFoundryLoginCheck(t *testing.T) {
|
||||
// should never used in productive environment, but it is useful for rapid prototyping/troubleshooting
|
||||
CfAPIOpts: []string{"--skip-ssl-validation"},
|
||||
}
|
||||
loggedIn, err := LoginCheck(cfconfig)
|
||||
|
||||
cf := CFUtils{Exec: m}
|
||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
||||
if assert.NoError(t, err) {
|
||||
assert.True(t, loggedIn)
|
||||
assert.Equal(t, []mock.ExecCall{
|
||||
@ -86,17 +86,13 @@ func TestCloudFoundryLogin(t *testing.T) {
|
||||
|
||||
m := &mock.ExecMockRunner{}
|
||||
|
||||
defer func() {
|
||||
c = &command.Command{}
|
||||
}()
|
||||
c = m
|
||||
|
||||
t.Run("CF Login: missing parameter", func(t *testing.T) {
|
||||
|
||||
defer loginMockCleanup(m)
|
||||
|
||||
cfconfig := LoginOptions{}
|
||||
err := Login(cfconfig)
|
||||
cf := CFUtils{Exec: m}
|
||||
err := cf.Login(cfconfig)
|
||||
assert.EqualError(t, err, "Failed to login to Cloud Foundry: Parameters missing. Please provide the Cloud Foundry Endpoint, Org, Space, Username and Password")
|
||||
})
|
||||
t.Run("CF Login: failure", func(t *testing.T) {
|
||||
@ -114,7 +110,8 @@ func TestCloudFoundryLogin(t *testing.T) {
|
||||
Password: "testPassword",
|
||||
}
|
||||
|
||||
err := Login(cfconfig)
|
||||
cf := CFUtils{Exec: m}
|
||||
err := cf.Login(cfconfig)
|
||||
if assert.EqualError(t, err, "Failed to login to Cloud Foundry: wrong password or account does not exist") {
|
||||
assert.Equal(t, []mock.ExecCall{
|
||||
mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}},
|
||||
@ -143,7 +140,8 @@ func TestCloudFoundryLogin(t *testing.T) {
|
||||
Username: "testUser",
|
||||
Password: "testPassword",
|
||||
}
|
||||
err := Login(cfconfig)
|
||||
cf := CFUtils{Exec: m}
|
||||
err := cf.Login(cfconfig)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, []mock.ExecCall{
|
||||
mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}},
|
||||
@ -180,7 +178,8 @@ func TestCloudFoundryLogin(t *testing.T) {
|
||||
"--skip-ssl-validation",
|
||||
},
|
||||
}
|
||||
err := Login(cfconfig)
|
||||
cf := CFUtils{Exec: m}
|
||||
err := cf.Login(cfconfig)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, []mock.ExecCall{
|
||||
mock.ExecCall{Exec: "cf", Params: []string{
|
||||
@ -206,7 +205,8 @@ func TestCloudFoundryLogin(t *testing.T) {
|
||||
|
||||
func TestCloudFoundryLogout(t *testing.T) {
|
||||
t.Run("CF Logout", func(t *testing.T) {
|
||||
err := Logout()
|
||||
cf := CFUtils{Exec: &mock.ExecMockRunner{}}
|
||||
err := cf.Logout()
|
||||
if err == nil {
|
||||
assert.Equal(t, nil, err)
|
||||
} else {
|
||||
@ -227,7 +227,8 @@ func TestCloudFoundryReadServiceKeyAbapEnvironment(t *testing.T) {
|
||||
Password: "testPassword",
|
||||
}
|
||||
var abapKey ServiceKey
|
||||
abapKey, err := ReadServiceKeyAbapEnvironment(cfconfig, true)
|
||||
cf := CFUtils{Exec: &command.Command{}}
|
||||
abapKey, err := cf.ReadServiceKeyAbapEnvironment(cfconfig, true)
|
||||
assert.Equal(t, "", abapKey.Abap.Password)
|
||||
assert.Equal(t, "", abapKey.Abap.Username)
|
||||
assert.Equal(t, "", abapKey.Abap.CommunicationArrangementID)
|
||||
|
@ -5,14 +5,21 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//ReadServiceKeyAbapEnvironment from Cloud Foundry and returns it.
|
||||
//Depending on user/developer requirements if he wants to perform further Cloud Foundry actions the cfLogoutOption parameters gives the option to logout after reading ABAP communication arrangement or not.
|
||||
func ReadServiceKeyAbapEnvironment(options ServiceKeyOptions, cfLogoutOption bool) (ServiceKey, error) {
|
||||
func (cf *CFUtils) ReadServiceKeyAbapEnvironment(options ServiceKeyOptions, cfLogoutOption bool) (ServiceKey, error) {
|
||||
|
||||
_c := cf.Exec
|
||||
|
||||
if _c == nil {
|
||||
_c = &command.Command{}
|
||||
}
|
||||
|
||||
var abapServiceKey ServiceKey
|
||||
var err error
|
||||
|
||||
@ -25,16 +32,16 @@ func ReadServiceKeyAbapEnvironment(options ServiceKeyOptions, cfLogoutOption boo
|
||||
Password: options.Password,
|
||||
}
|
||||
|
||||
err = Login(config)
|
||||
err = cf.Login(config)
|
||||
var serviceKeyBytes bytes.Buffer
|
||||
c.Stdout(&serviceKeyBytes)
|
||||
_c.Stdout(&serviceKeyBytes)
|
||||
if err == nil {
|
||||
//Reading Service Key
|
||||
log.Entry().WithField("cfServiceInstance", options.CfServiceInstance).WithField("cfServiceKey", options.CfServiceKey).Info("Read service key for service instance")
|
||||
|
||||
cfReadServiceKeyScript := []string{"service-key", options.CfServiceInstance, options.CfServiceKey}
|
||||
|
||||
err = c.RunExecutable("cf", cfReadServiceKeyScript...)
|
||||
err = _c.RunExecutable("cf", cfReadServiceKeyScript...)
|
||||
}
|
||||
if err == nil {
|
||||
var serviceKeyJSON string
|
||||
@ -54,7 +61,7 @@ func ReadServiceKeyAbapEnvironment(options ServiceKeyOptions, cfLogoutOption boo
|
||||
if err != nil {
|
||||
if cfLogoutOption == true {
|
||||
var logoutErr error
|
||||
logoutErr = Logout()
|
||||
logoutErr = cf.Logout()
|
||||
if logoutErr != nil {
|
||||
return abapServiceKey, fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
|
||||
}
|
||||
@ -65,7 +72,7 @@ func ReadServiceKeyAbapEnvironment(options ServiceKeyOptions, cfLogoutOption boo
|
||||
//Logging out of CF
|
||||
if cfLogoutOption == true {
|
||||
var logoutErr error
|
||||
logoutErr = Logout()
|
||||
logoutErr = cf.Logout()
|
||||
if logoutErr != nil {
|
||||
return abapServiceKey, fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user